1 回调函数的this不符合直觉
const name = 1;
const MyObj = {
name: 2,
showName: function () {
console.log(this.name);
}
}
setTimeout(MyObj.showName, 1000);
上面的代码运行结果是:打印1,而不是2。因为setTimeout()的回调函数运行在独立的执行环境上。这导致了,无论在严格还是非严格模式下,回调函数的 this 都会指向 window 对象,这和所期望的this的值是不一样的。
这里列举三种解决方案:
- 箭头函数
setTimeout(()=>{MyObj.showName()}, 1000);
- 包装函数
setTimeout(function(){MyObj.showName()}, 1000);
- bind方法
setTimeout(MyObj.showName.bind(MyObj), 1000);
2 超时延迟
setTimeout未必会按照延迟时间准时执行。
function bar() {
console.log('bar')
}
function foo() {
setTimeout(bar, 0);
for (let i = 0; i < 5000; i++) {
console.log(i);
}
}
foo()
上面的代码运行结果是:直到输出4999,才最终打印"bar"。其中的原因就是当前任务执行时间过久,从而导致setTimeout的任务被延后执行了。
3 最大延迟时限
包括 IE, Chrome, Safari, Firefox 在内的浏览器,其内部以32位带符号整数存储延迟时限。因此,当延迟时限大于 2147483647(2^31-1)毫秒 (大约24.8天)时就会溢出,导致定时器将会被立即执行。
function sayHi(str) {
console.log(str)
}
setTimeout(sayHi, 2147483647, 'hi');
setTimeout(sayHi, 2147483648, 'hello');
以上代码会立即打印"hello",2147483647毫秒后才会打印"hi"。
4 最小延迟时限
如果 setTimeout 存在嵌套调用,那么系统会设置最短时间间隔为 4 毫秒。
let current=new Date().getTime();
function sayTime() {
console.log(new Date().getTime()-current)
current=new Date().getTime();
setTimeout(sayTime, 1);
}
setTimeout(sayTime, 1);
运行以上代码,除了前几次的打印结果可能小于4之外,之后的打印结果均大于4.
5 未激活页的最小时限
为了优化后台tab的加载损耗以及降低耗电量,在未被激活的tab中定时器的最小延时限制为1000毫秒。 可以同样用第4节中的代码,切换一会儿tab,再查看控制台时会发现打印结果在1000左右。
总结
- setTimeout中的回调函数的this指向window对象;
- 当前任务执行过久时,可能导致setTimeout的任务超时延迟执行;
- setTimeout的最大时限为2147483647(2^31-1)毫秒,超出则立即执行;
- 对于深层嵌套的setTimeout,最小延迟为4毫秒;
- 未激活页的最小时限为1000毫秒。
参考
本文使用 mdnice 排版