浏览器工作原理与实践
李兵
前盛大创新院高级研究员
56402 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 46 讲
浏览器工作原理与实践
15
15
1.0x
00:00/00:00
登录|注册

16 | WebAPI:setTimeout是如何实现的?

触发延迟队列
定时器回调任务添加
事件执行顺序
消息队列
分析requestAnimationFrame优势
对比setTimeout
requestAnimationFrame工作机制
存在陷阱
实时性不足
延时队列支持
setTimeout回调函数中的this指向问题
延时执行时间最大值
未激活页面最小间隔为1000毫秒
嵌套调用最短时间间隔为4毫秒
任务执行时间过久影响定时器任务
取消定时器操作
延迟执行队列
事件循环系统
取消定时器
返回定时器编号
定时器
思考时间
总结
使用setTimeout注意事项
浏览器实现setTimeout
setTimeout介绍
WebAPI setTimeout实现

该思维导图由 AI 生成,仅供参考

上一篇文章中我们介绍了页面中的事件和消息队列,知道了浏览器页面是由消息队列和事件循环系统来驱动的
那在接下来的两篇文章中,我会通过 setTimeoutXMLHttpRequest 这两个 WebAPI 来介绍事件循环的应用。这两个 WebAPI 是两种不同类型的应用,比较典型,并且在 JavaScript 中的使用频率非常高。你可能觉得它们太简单、太基础,但有时候恰恰是基础简单的东西才最重要,了解它们是如何工作的会有助于你写出更加高效的前端代码。
本篇文章主要介绍的是 setTimeout。其实说起 setTimeout 方法,从事开发的同学想必都不会陌生,它就是一个定时器,用来指定某个函数在多少毫秒之后执行。它会返回一个整数,表示定时器的编号,同时你还可以通过该编号来取消这个定时器。下面的示例代码就演示了定时器最基础的使用方式:
function showName(){
console.log("极客时间")
}
var timerID = setTimeout(showName,200);
执行上述代码,输出的结果也很明显,通过 setTimeout 指定在 200 毫秒之后调用 showName 函数,并输出“极客时间”四个字。
简单了解了 setTimeout 的使用方法后,那接下来我们就来看看浏览器是如何实现定时器的,然后再介绍下定时器在使用过程中的一些注意事项。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

WebAPI中的setTimeout方法是前端开发中常用的定时器,用于指定某个函数在一定时间后执行。本文通过介绍浏览器实现定时器的原理,强调了长任务执行时间过久会影响定时器任务的执行,以及嵌套调用setTimeout会导致系统设置最短时间间隔为4毫秒。此外,还提到了未激活的页面中定时器最小值大于1000毫秒,延时值溢出会导致定时器立即执行,以及使用setTimeout设置的回调函数中的this不符合直觉的问题。文章建议对于一些时间精度要求比较高的需求,应该有针对性地采取其他方案。读者在使用setTimeout时需要注意这些细节,以编写高效的前端代码。同时,文章提出了作业,要求读者了解requestAnimationFrame的工作机制,并分析其实现的动画效果比setTimeout好的原因。通过本文的分析和讲解,读者可以深入理解setTimeout的工作原理和注意事项,以及学习到适合不同需求的定时器选择。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《浏览器工作原理与实践》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(88)

  • 最新
  • 精选
  • Angus
    我没有太理解这个异步延迟队列,既然是队列,但好像完全不符合先进先出的特点。在每次执行完任务队列中的一个任务之后都会去执行那些已经到期的延迟任务,这些延迟的任务具体是如何取出的呢。

    作者回复: 我文章说是队列,为了和消息队列统一起来,不然表述起来有点拗口。 其实是一个hashmap结构,等到执行这个结构的时候,会计算hashmap中的每个任务是否到期了,到期了就去执行,直到所有到期的任务都执行结束,才会进入下一轮循环!

    2019-09-10
    5
    103
  • mfist
    requestAnimationFrame 提供一个原生的API去执行动画的效果,它会在一帧(一般是16ms)间隔内根据选择浏览器情况去执行相关动作。 setTimeout是在特定的时间间隔去执行任务,不到时间间隔不会去执行,这样浏览器就没有办法去自动优化。 今日得到 浏览器的页面是通过消息队列和事件循环系统来驱动的。settimeout的函数会被加入到延迟消息队列中, 等到执行完Task任务之后就会执行延迟队列中的任务。然后分析几种场景下面的setimeout的执行方式。 1. 如果执行一个很耗时的任务,会影响延迟消息队列中任务的执行 2. 存在嵌套带调用时候,系统会设置最短时间间隔为4s(超过5层) 3. 未激活的页面,setTimeout最小时间间隔为1000ms 4. 延时执行时间的最大值2147483647,溢出会导致定时器立即执行 5. setTimeout设置回调函数this会是回调时候对应的this对象,可以使用箭头函数解决

    作者回复: 回答的很棒,raf是按照系统刷新的节奏调用的!

    2019-09-11
    3
    57
  • 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-18
    8
    21
  • Djan Unchained
    requestAnimationFrame 也是在主线程上执行吗?如果当前任务执行时间过久,也会导致 requestAnimationFrame 被延后执行吗?

    作者回复: 是的,raf的回调函数也是在主线程上执行的,如果其中的一个回调函数执行过久,会影响到其他的任务的

    2019-10-25
    11
  • 老师,你好。 请问微任务的执行是在延迟队列任务执行之前吗?

    作者回复: 没有之前之后啊,延时队列里面是宏任务,普通的消息队列里面也是宏任务,微任务是在宏任务快要执行结束之前执行的!

    2019-09-17
    6
    11
  • Zzzrd
    看完还是很迷惑: 1. setTimeout是宏任务,宏任务应该放在消息队列中,文中说是放在延迟队列中,为什么?延迟队列和消息队列的区别是什么? 2. 延迟队列的任务是在当前宏任务执行完之后执行,微任务队列是在当前宏任务将要结束时执行对吗?

    作者回复: 延迟队列也是宏任务,实际上blink维护了很多不同优先级的队列,这些队列里面都是宏任务 微任务是在宏任务执行过程中的某个时间点执行的,通常是在宏任务快要结束的时候执行

    2019-12-19
    4
    10
  • 李懂
    1.执行延迟队列的任务,是一次循环只取出一个,还是检查只要时间到了,就执行? 2.微任务是在宏任务里的,是执行完一个宏任务,就去执行宏任务里面的微任务?

    作者回复: 比如有五个定时的任务到期了,那么会分别把这个五个定时器的任务执行掉,再开始下次循环过程! chromium中,当执行一个宏任务时,才会创建微任务队列,等遇到checkpoint时就会执行微任务!

    2019-09-10
    3
    9
  • Wlt
    老师,您好,延迟队列和消息队列是什么关系,怎么配合工作的?

    作者回复: 延迟消息队列主要是放一些定时执行的任务,如JavaScript设置定时器的回调,还有浏览器内部的一些定时回调任务! 这类任务需要等到指定时间间隔之后才会被执行! 而正常的消息队列中的任务只会按照顺序执行,执行完上个任务接着执行下个任务,不需要关系时间间隔!

    2019-10-28
    8
  • Cris
    老师,您这里未激活的页面是什么意思?

    作者回复: 就是后台页面,比如你在浏览器中打开了多个标签,除了你当前操作的页面,其他的标签页都是后台页面

    2020-01-03
    5
  • 纪年
    如果 setTimeout 设置的延迟值大于 2147483647 毫秒时就会溢出,这导致定时器会被立即执行。 问题:这里的立即执行其实是不是相当于setTimeout(fun, 0)的意思?

    作者回复: 是的,说立即执行的确有点不准确哈,这个我来优化下说法!

    2019-11-23
    4
收起评论
显示
设置
留言
88
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部