Karam
Articles34
Tags31
Categories11
setTimeout是如何实现的

setTimeout是如何实现的

setTimeout是指定多少毫秒的时间后执行某个方法的API

浏览器怎么实现定时器

Chorme浏览器除了正常使用的消息队列以外,还有一个消息队列用于处理需要延迟执行的任务,包括了定时器和Chomium的一些延迟任务,所以当Javascript创建一个定时器的时候,会放入浏览器的延迟队列中等待执行
当创建一个定时器的时候,渲染进程会创建一个回调任务,里面包含回调函数,开始时间,延迟时间,函数的showName
延迟队列的任务的执行是通过开始时间和延迟时间计算出任务的到期时间,然后执行延迟队列中的到期任务,执行完后再进入下一个循环。
设置一个定时器,JS会返回定时器的ID,可以根据定时器的ID清除未开始执行的延时任务;浏览器内部删除定时器是根据定时器的ID,在延迟队列中找到任务并清除出队列

使用定时器的注意事项

  1. 避免长任务导致延迟
  2. 避免定时器嵌套
  3. 未激活的界面,最小延迟时间为1000ms
  4. 设置延迟时间有最大值,24.8天,超过这个时间就会溢出,函数立即执行
  5. 定时器的this可能会不一致,在严格模式下,定时器的this是undefined,非严格模式下为window,要避免这个情况可以使用匿名函数或者使用bind绑定this

    setImmediate

    setTimeout的最小延迟时间在4ms,而setImmediate的最小延迟时间可以在1ms以内

其他异步模型

requestAnimationFrame

requestAnimationFrame和屏幕刷新频率同步,在不支持requestAnimationFrame的浏览器中,只能使用setTimeout或者setInterval来实现动画,这样连续几次修改dom就会造成丢帧,卡顿的现象

Promise

如果想要任务在下一次事件循环后执行的话,使用Promise比setTimeout(0)先执行

process.nextTick

process.nextTick比Promise更早执行,他不会进入延迟队列中,而是直接强插入主线程得任务列表中,不会阻塞主线程,但是会阻塞延迟队列中的任务执行,如果嵌套process.nextTick可能会导致异步任务一直不能执行