如何实现setTimeout-爱代码爱编程
setTimeout就是一个定时器,用来指定某个函数在多少毫秒之后执行。它会返回一个整数,表示定时器的编号,同时你还可以通过该编号来取消这个定时器。
要执行一段异步任务,需要先将任务添加到消息队列中。不过通过定时器设置回调函数有点特别,它们需要在指定的时间间隔内被调用,但消息队列中的任务是按照顺序执行的,所以为了保证回调函数能在指定时间内执行,你不能将定时器的回调函数直接添加到消息队列中。
在 Chrome 中除了正常使用的消息队列之外,还有另外一个消息队列(定时器线程上的消息队列吧),这个队列中维护了需要延迟执行的任务列表,包括了定时器和 Chromium 内部一些需要延迟执行的任务。所以当通过 JavaScript 创建一个定时器时,渲染进程会将该定时器的回调任务添加到延迟队列中。
延迟队列也是宏任务,实际上blink维护了很多不同优先级的队列,这些队列里面都是宏任务。微任务是在宏任务执行过程中的某个时间点执行的,通常是在宏任务快要结束的时候执行。
延迟队列会根据发起时间和延迟时间计算出到期的任务,然后依次执行这些到期的任务。等到期的任务执行完成之后,再继续下一个循环过程。通过这样的方式,一个完整的定时器就实现了。
当一个定时器的任务还没有被执行的时候,也是可以取消的,具体方法是调用 clearTimeout 函数,并传入需要取消的定时器的 ID。浏览器内部实现取消定时器的操作就是直接从延迟队列中,通过 ID 查找到对应的任务,然后再将其从队列中删除掉就可以了。
使用 setTimeout 的一些注意事项
- 如果当前任务执行时间过久,会影响定时器任务的执行
- 如果 setTimeout 存在嵌套调用,那么系统会设置最短时间间隔为 4 毫秒
嵌套调用超过五次以上,后面每次的调用最小时间间隔是 4 毫秒。之所以出现这样的情况,是因为在 Chrome 中,定时器被嵌套调用 5 次以上,系统会判断该函数方法被阻塞了,如果定时器的调用时间间隔小于 4 毫秒,那么浏览器会将每次调用的时间间隔设置为 4 毫秒。 - 未激活的页面,setTimeout 执行最小间隔是 1000 毫秒
- 延时执行时间有最大值
Chrome、Safari、Firefox 都是以 32 个 bit 来存储延时值的,32bit 最大只能存放的数字是 2147483647 毫秒,这就意味着,如果 setTimeout 设置的延迟值大于 2147483647 毫秒(大约 24.8 天)时就会溢出,那么相当于延时值被设置为 0 。 - 使用 setTimeout 设置的回调函数中的 this 不符合直觉
在编译的时候,执行上下文中的 this 会被设置为全局 window,如果是严格模式,会被设置为 undefined。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接: https://blog.csdn.net/lovermeiy/article/details/111052539