定时器详解和应用、js加载阻塞、css加载阻塞
1.setTimeout()、setInterval()详解和应用
1.1 详解: setTimeout、setInterval执行时机
1.2 存在问题: setInterval重复定时器可能存在的问题、解决方案
1.3 应用: Yeilding Processes(进程暂停)
运行在浏览器中的JavaScript都被分配了一个确定数量的资源,不同于桌面应用往往能够随意控制他们要的内存大小和处理时间,Javascript被严格限制了,以防止恶意的Web程序员吧用的计算机搞挂了,其中一个限制是长时间运行脚本的制约,如果代码运行超过特定时长或者特定数量的语句就不让它继续执行,询问是允许其继续执行还是停止它。所有JavaScript开发人员的目标就是,确保用户永远不会再浏览器中看到这个令人费解的对话框。定时器是绕开此限制的方法之一
脚本运行时间长的2个原因:
1.过长的、过深嵌套的函数调用;
2.进行大量处理的循环;
这2种后者较为容易的被解决
进行大量处理的循环:
使用这种方式必须满足的要求:
1.该处理不是必须同步完成
2.数据不是必须按顺序完成
解决方案:数组分块
function chunk(arr, process, context){
setTimeout(function () {
var item = arr.shift()
process.call(context, item)
if(arr.length > 0){
setTimeout(arguments.callee, 100)
}
}, 100)
}
使用场景建议:
一旦某个函数的执行需要花50ms以上的时间完成,那么最好看看能否将任务分割为一系列可以使用定时器的小任务。
1.4 应用:函数节流
1.4.1 节流函数的起源
浏览器中的某些计算和处理要比其他的开销大很多。例如,DOM比起非DOM交互需要更多的内存和CUP时间。连续尝试进行过多的DOM相关操作可能会导致浏览器挂起,有时候甚至奔溃。尤其在IE中使用onresize时处理程序的时候很容易发生,当调整浏览器大小的时候,该事件会连续触发。在onresize事件处理程序内部如果尝试进行DOM操作,其高频率的更改可能会让浏览器奔溃。为了绕开这个问题,可以使用定时器对该函数进行节流。
**1.4.2 节流函数的原理 **
某段代码不能在没有间隔的情况下连续重复执行。
第一次调用函数,创建一个定时器,在指定的时间间隔后执行代码,当第二次调用该函数时,他会清除前一次的定时器并设置另一个定时器。如果前一个定时器已经执行了,这个操作没有任何意义。然后,如果前一个定时器尚未执行,其实就是将其替换为一个新的定时器。目的只有一个:只有在执行函数的请求停止了一段时间之后才执行。
1.4.3 适合节流的场景:周期性执行的代码
**1.4.4 节流函数的实现 **
var processor = {
timeoutId: null,
performProcessing: function () {
//实际执行的代码
},
process: function () {
clearTimeout(this.timeoutId)
var that = this
this.timeoutId = setTimeout(function () {
that.performProcessing()
}, 100)
}
}
**1.4.5 节流函数实现的简化 **
function throttle (cb, context) {
clearTimeout(cb.ID)
cb.ID = setTimeout(function () {
cb.call(context)
}, 1000)
}
2.CSS加载是否影响DOM的解析和渲染
给浏览器设置节流和延迟:使出现的效果能够在自己被自己察觉。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
h1 {
color: red!important;
}
</style>
<script>
function h () {
let h1 = document.getElementById('h1')
console.log( h1 )
}
setTimeout(h, 0)
</script>
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>
<body>
<h1 id="h1">这是红色</h1>
</body>
</html>
结果:在css正在下载时,h1标签被控制太打印出来,但是页面没有文字。
结论:css加载会阻塞DOM树渲染,不会阻塞DOM树的解析。
个人看法:这样子做还是符合优化的正常逻辑的,css不会阻塞解析;如果不阻塞css渲染,等这个css加载完成后,会触发回流和重绘额外增加性能开销,所以还不如直接等css加载完成后再来渲染。
3.css加载是否影响js加载?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
h1 {
color: red!important;
}
</style>
<script>
console.log('before css')
var startDate = new Date()
</script>
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>
<body>
<h1 id="h1">这是红色</h1>
<script>
var endData = new Date()
console.log('after css')
console.log('已经过了' + (endData - startDate))
</script>
</body>
</html>
结果:在css正在加载时,控制台内容:before css
css加载完成时,控制台内容:
before css
after css
已经过了3444
结论:css加载时,会阻塞js的执行。
4.js加载是否影响DOM的解析和渲染、js执行、css加载?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.slim.min.js"></script>
<script>
console.log(1111)
</script>
<style>
h1 {
color: red!important;
}
</style>
</head>
<body>
<h1 id="h1">这是红色</h1>
</body>
</html>
现象:Loading js时,后续js没有执行,后续DOM没有解析。
结论:js加载阻塞