WebAPI: setTimeout是如何实现的?

为了支持定时器的实现,浏览器增加了延时队列

由于消息队列排队和一些系统级别的限制,通过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是在特定的时间间隔去执行任务,不到时间间隔不会执行,这样浏览器就没办法自动优化。并且还会因为一些原因延迟执行

原文地址:https://www.cnblogs.com/zpsakura/p/13886088.html