为了支持定时器的实现,浏览器增加了延时队列。
由于消息队列排队和一些系统级别的限制,通过setTimeout设置的回调任务并非总是可以实时地被执行,这样就不能满足一些实时性要求较高的需求了。
定时器在使用过程中存在一些陷阱,如:
-
如果当前任务执行时间过久,会影响延迟到期定时器任务的执行
-
如果
setTimeout
存在嵌套调用,那么系统会设置最短时间间隔为 4 毫秒function cb() { setTimeout(cb, 0); } setTimeout(cb, 0);
原因:在Chrome中,定时器被嵌套调用5次以上,系统会判断该函数方法被阻塞了,如果定时器的调用事件间隔小于4毫秒,浏览器会将每次调用的时间间隔设置为4毫秒。因此不太适合实时性较高的需求,比如通过setTimeout来实现JavaScript动画。
- 未激活的页面,setTimeout执行最小间隔是1000毫秒
目的:是为了优化后台页面的加载损耗以及降低耗电量
- 延时执行时间有最大值
因为Chrome,Safari,Firefox都是以32个bit来存储延时值的,32bit最大只能存放的数字是2147483647(大约24.8天),超过则溢出,导致定时器会被立即执行。
- 使用setTimeout设置的回调函数中的this不符合直觉
var name = 1;
var Myobj = {
name: 2,
showName: function() {
console.log(this.name);
}
}
setTimeout(Myobj.showName, 1000) =======> 打印出1
回调函数中,执行上下文中的this,会被设置为全局window, 严格模式下,设置为undefined。
解决方法:
-
将Myobj.showName放在匿名函数中执行
// 箭头函数 setTimeout(() => { MyObj.showName()}, 1000); // 或者 function 函数 setTimeout(function() { MyObj.showName();}, 1000)
-
使用bind方法,将showName绑定在Myobj上
setTimeout(MyObj.showName.bind(MyObj), 1000)
requestAnimationFrame实现的动画效果比setTimeout好的原因?
requestAnimationFrame
是按照系统刷新的节奏调用的,而setTimeout
是在特定的时间间隔去执行任务,不到时间间隔不会执行,这样浏览器就没办法自动优化。并且还会因为一些原因延迟执行