定时器,用来指定某个函数在多少毫秒之后执行。setTimeout(code/function, milliseconds, param1, param2, ...)
。返回一个整数,表示定时器的编号,可以通过该编号来取消这个定时器。
- 为了支持定时器的实现,浏览器增加了延时队列(事件添加在消息队列, 按照消息队列顺序执行)
- 由于消息队列排队和一些系统级别的限制,setTimeout 没有被实时执行
- 当前任务执行过久,影响定时器任务的执行
定时器注意事项
渲染进程将会创建一个回调任务,包含了回调函数 showName、当前发起时间、延迟执行时间
- 将该任务添加到延时执行队列
DelayedIncomingQueue delayed_incoming_queue;
处理完消息队列中的一个任务之后,就开始执行 ProcessDelayTask 函数(专门用来处理延迟执行任务)。ProcessDelayTask 函数会根据发起时间和延迟时间计算出到期的任务,然后依次执行这些到期的任务。等到期的任务执行完成之后,再继续下一个循环过程。
clearTimeout函数,浏览器内部通过id查到对应任务,从延时队列删除。
什么情况下没有实时执行?
function bar() {
console.log('bar')
}
function foo() {
setTimeout(bar, 0);
for (let i = 0; i < 5000; i++) {
let i = 5+8+8+8
console.log(i)
}
}
foo() // 耗时500ms
短时间间隔为4ms
执行结果:嵌套调用超过五次以上,后面每次的调用最小时间间隔是 4 毫秒。
原因:在 Chrome 中,定时器被嵌套调用 5 次以上,系统会判断该函数方法被阻塞了,如果定时器的调用时间间隔小于 4 毫秒,那么浏览器会将每次调用的时间间隔设置为 4 毫秒。
解决:requestAnimationFrame 代替 setTimeout 实现的动画
最小时间间隔为1000ms
如果标签不是当前的激活标签,那么定时器最小的时间间隔是 1000 毫秒,目的是为了优化后台页面的加载损耗以及降低耗电量
改变this指向
- requestAnimationFrame 实现的动画效果比 setTimeout 好?
使用 requestAnimationFrame 不需要设置具体的时间,由系统来决定回调函数的执行时间,requestAnimationFrame 里面的回调函数是在页面刷新之前执行,它跟着屏幕的刷新频率走,保证每个刷新间隔只执行一次,内如果页面未激活的话,requestAnimationFrame 也会停止渲染,这样既可以保证页面的流畅性,又能节省主线程执行函数的开销
实战:
/*
1.从start至end,每隔100毫秒console.log一个数字,每次数字增幅为1
2.返回的对象中需要包含一个cancel方法,用于停止定时操作
3.第一个数字需要立即输出
*/