16 | WebAPI:setTimeout是如何实现的?
该思维导图由 AI 生成,仅供参考
- 深入了解
- 翻译
- 解释
- 总结
WebAPI中的setTimeout方法是前端开发中常用的定时器,用于指定某个函数在一定时间后执行。本文通过介绍浏览器实现定时器的原理,强调了长任务执行时间过久会影响定时器任务的执行,以及嵌套调用setTimeout会导致系统设置最短时间间隔为4毫秒。此外,还提到了未激活的页面中定时器最小值大于1000毫秒,延时值溢出会导致定时器立即执行,以及使用setTimeout设置的回调函数中的this不符合直觉的问题。文章建议对于一些时间精度要求比较高的需求,应该有针对性地采取其他方案。读者在使用setTimeout时需要注意这些细节,以编写高效的前端代码。同时,文章提出了作业,要求读者了解requestAnimationFrame的工作机制,并分析其实现的动画效果比setTimeout好的原因。通过本文的分析和讲解,读者可以深入理解setTimeout的工作原理和注意事项,以及学习到适合不同需求的定时器选择。
《浏览器工作原理与实践》,新⼈⾸单¥59
全部留言(88)
- 最新
- 精选
- Angus我没有太理解这个异步延迟队列,既然是队列,但好像完全不符合先进先出的特点。在每次执行完任务队列中的一个任务之后都会去执行那些已经到期的延迟任务,这些延迟的任务具体是如何取出的呢。
作者回复: 我文章说是队列,为了和消息队列统一起来,不然表述起来有点拗口。 其实是一个hashmap结构,等到执行这个结构的时候,会计算hashmap中的每个任务是否到期了,到期了就去执行,直到所有到期的任务都执行结束,才会进入下一轮循环!
2019-09-105103 - mfistrequestAnimationFrame 提供一个原生的API去执行动画的效果,它会在一帧(一般是16ms)间隔内根据选择浏览器情况去执行相关动作。 setTimeout是在特定的时间间隔去执行任务,不到时间间隔不会去执行,这样浏览器就没有办法去自动优化。 今日得到 浏览器的页面是通过消息队列和事件循环系统来驱动的。settimeout的函数会被加入到延迟消息队列中, 等到执行完Task任务之后就会执行延迟队列中的任务。然后分析几种场景下面的setimeout的执行方式。 1. 如果执行一个很耗时的任务,会影响延迟消息队列中任务的执行 2. 存在嵌套带调用时候,系统会设置最短时间间隔为4s(超过5层) 3. 未激活的页面,setTimeout最小时间间隔为1000ms 4. 延时执行时间的最大值2147483647,溢出会导致定时器立即执行 5. setTimeout设置回调函数this会是回调时候对应的this对象,可以使用箭头函数解决
作者回复: 回答的很棒,raf是按照系统刷新的节奏调用的!
2019-09-11357 - moss这一节学习到了不少setTimeout的知识。不过关于消息队列我有不同的理解。 1. 关于任务优先级。whatwg标准里,“An event loop has one or more task queues”。消息队列其实不算是队列,因为有很多个task queue。“a task queue is a set of tasks”。每一个task queue才是一个队列。而对于每一个task queue里的task,其task source是一致的,或者说不同的task source会被推入到不同的task queue。就是规范里说的“every task source must be associated with a specific task queue”。而task sources都有哪些呢?比如DOM操作,UI事件,网络事件等。这个setTimout应该也算是一种task source吧?会放到专门的队列里。上一轮事件循环结束后,会先选择一个高优先级的task queue,然后取出task queue的第一个task,也因此而有了事件的优先级,老师将的延时队列我有点不太知道怎么融入我现有的知识体系。 2. “重新布局”是task吗? 老师说“重新布局”的事件会被放到消息队列。我的理解是task -> microtask -> update the rendering。当然不是每次循环都走渲染过程,因为每次循环都特别快不可能每次都走一次渲染,浏览器会遵循17ms一桢的原则走一次update the rendering,其中rAF也在此阶段执行,也是老师题目里rAF更流畅的原因。而重新布局也是在update the rendering阶段执行的,resize和onscroll都是在update the rendering阶段。标准里在update the rendering阶段,会有“run the resize steps”,“run the scroll steps”,这也是为啥scrolling自带节流效果最多17ms触发一次回调的原因,所以我认为连续事件(resize,scroll)既然都不是task -> microtask -> update the rendering里的task,而是update the rendering阶段,应该不会推送到某一个task queue才对。
作者回复: 第一个问题我在18节也回答过了,一个是标准,一个是实现,标准定义了很多队列,而浏览器只实现了一个普通队列和一个延时队列! 第二个问题,你说的那个update the randering就是说rAF吧?rAF是用户调用的,重新布局是渲染引擎自动安排的任务,必然要放到消息队列中! 滚动一般默认都是在合成线程里面完成的,这种都没用到主线程
2019-09-18821 - Djan UnchainedrequestAnimationFrame 也是在主线程上执行吗?如果当前任务执行时间过久,也会导致 requestAnimationFrame 被延后执行吗?
作者回复: 是的,raf的回调函数也是在主线程上执行的,如果其中的一个回调函数执行过久,会影响到其他的任务的
2019-10-2511 - 淡老师,你好。 请问微任务的执行是在延迟队列任务执行之前吗?
作者回复: 没有之前之后啊,延时队列里面是宏任务,普通的消息队列里面也是宏任务,微任务是在宏任务快要执行结束之前执行的!
2019-09-17611 - Zzzrd看完还是很迷惑: 1. setTimeout是宏任务,宏任务应该放在消息队列中,文中说是放在延迟队列中,为什么?延迟队列和消息队列的区别是什么? 2. 延迟队列的任务是在当前宏任务执行完之后执行,微任务队列是在当前宏任务将要结束时执行对吗?
作者回复: 延迟队列也是宏任务,实际上blink维护了很多不同优先级的队列,这些队列里面都是宏任务 微任务是在宏任务执行过程中的某个时间点执行的,通常是在宏任务快要结束的时候执行
2019-12-19410 - 李懂1.执行延迟队列的任务,是一次循环只取出一个,还是检查只要时间到了,就执行? 2.微任务是在宏任务里的,是执行完一个宏任务,就去执行宏任务里面的微任务?
作者回复: 比如有五个定时的任务到期了,那么会分别把这个五个定时器的任务执行掉,再开始下次循环过程! chromium中,当执行一个宏任务时,才会创建微任务队列,等遇到checkpoint时就会执行微任务!
2019-09-1039 - Wlt老师,您好,延迟队列和消息队列是什么关系,怎么配合工作的?
作者回复: 延迟消息队列主要是放一些定时执行的任务,如JavaScript设置定时器的回调,还有浏览器内部的一些定时回调任务! 这类任务需要等到指定时间间隔之后才会被执行! 而正常的消息队列中的任务只会按照顺序执行,执行完上个任务接着执行下个任务,不需要关系时间间隔!
2019-10-288 - Cris老师,您这里未激活的页面是什么意思?
作者回复: 就是后台页面,比如你在浏览器中打开了多个标签,除了你当前操作的页面,其他的标签页都是后台页面
2020-01-035 - 纪年如果 setTimeout 设置的延迟值大于 2147483647 毫秒时就会溢出,这导致定时器会被立即执行。 问题:这里的立即执行其实是不是相当于setTimeout(fun, 0)的意思?
作者回复: 是的,说立即执行的确有点不准确哈,这个我来优化下说法!
2019-11-234