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

加餐二|任务调度:有了setTimeOut,为什么还要使用rAF?

队头阻塞问题的影响
第四次迭代:任务饿死
第三次迭代:动态调度策略
第二次迭代:根据消息类型实现不同优先级的消息队列
第一次迭代:引入一个高优先级队列
单消息队列的队头阻塞问题
Chromium 解决队头阻塞问题的方法
消息队列和事件循环系统
requestAnimationFrame 回调函数的执行时机
渲染进程的任务调度系统
为什么使用 rAF 而不是 setTimeout
任务调度

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

你好,我是李兵。
我们都知道,要想利用 JavaScript 实现高性能的动画,那就得使用 requestAnimationFrame 这个 API,我们简称 rAF,那么为什么都推荐使用 rAF 而不是 setTimeOut 呢?
要解释清楚这个问题,就要从渲染进程的任务调度系统讲起,理解了渲染进程任务调度系统,你自然就明白了 rAF 和 setTimeOut 的区别。其次,如果你理解任务调度系统,那么你就能将渲染流水线和浏览器系统架构等知识串起来,理解了这些概念也有助于你理解 Performance 标签是如何工作的。
要想了解最新 Chrome 的任务调度系统是怎么工作的,我们得先来回顾下之前介绍的消息循环系统,我们知道了渲染进程内部的大多数任务都是在主线程上执行的,诸如 JavaScript 执行、DOM、CSS、计算布局、V8 的垃圾回收等任务。要让这些任务能够在主线程上有条不紊地运行,就需要引入消息队列。
在前面的《16 | WebAPI:setTimeout 是如何实现的?》这篇文章中,我们还介绍了,主线程维护了一个普通的消息队列和一个延迟消息队列,调度模块会按照规则依次取出这两个消息队列中的任务,并在主线程上执行。为了下文讲述方便,在这里我把普通的消息队列和延迟队列都当成一个消息队列。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

JavaScript动画性能优化中,使用requestAnimationFrame(rAF)而不是setTimeout的原因在于渲染进程的任务调度系统。Chromium团队通过引入高优先级队列和动态调度策略,解决了单消息队列的队头阻塞问题,提高了页面加载速度。文章介绍了在不同场景下,Chromium如何动态调整消息队列的优先级,以满足不同场景的核心诉求。此外,文章还详细解释了VSync时钟同步周期和浏览器生成页面周期的关系,以及Chromium是如何利用VSync信号来优化交互阶段页面的任务调度策略的。最后,Chromium团队为了解决任务饿死问题,给每个队列设置了执行权重,缓解了任务饿死的情况。通过这些技术特点的总结,读者能快速了解文章内容,以及了解JavaScript动画性能优化的关键技术。

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

全部留言(33)

  • 最新
  • 精选
  • 木瓜777
    window.requestAnimationFrame 应该是在每一帧的开始就执行吧?

    作者回复: 应该说raf的回调任务会在每一帧的开始执行

    2019-11-29
    2
    33
  • Geek_0d3179
    如果raf的回调任务会在每一帧的开始执行,如果它执行时间很长(超过一帧),那就会阻碍后面所有任务的执行么?比如说用户的交互事件等高优先级任务也会受到影响导致卡顿么? 我在网上看到的资料:为啥是先执行用户的交互任务,在执行raf的回调???

    作者回复: 会啊,一个任务在执行的时候是不会被中断的,即使有再高优先级的任务,都需要等到当前dr任务执行结束,所以如果raf回调函数中的代码过于耗时的话,那么会影响渲染帧率! 等当前任务执行结束循环系统才会挑下个选优先级高的任务执行,因为用户输入的有限级高于raf的回调,所以会优先执行用户输入!

    2019-12-03
    15
  • gigot
    老师,我想问下在 primose.then 中执行宏任务(setTimeout或 ajax),其中该宏任务应该加入哪个事件队列。 是说微任务队列都是按顺序执行,其中每个微任务又有新的事件循环(包括宏任务和微任务),类似于新得全局环境,这样理解对吗

    作者回复: 不管在哪里请求setTimeout,它的回调函数都是在宏任务中执行的。 不过在微任务中产生了新的微任务,新的微任务还是在当前的微任务队列中,所以如果在微任务中不停产生新的微任务,是会阻塞页面的!

    2019-11-29
    3
    6
  • 王博
    觉得老师的绘图工具挺好的,老师可以推荐一下吗?谢谢

    作者回复: keynote啊

    2019-11-26
    3
  • wens
    react fiber的实现应该是借鉴了chromium的消息队列机制
    2020-05-25
    1
    12
  • 刘弥
    老师的图其实已经给出了答案,VSync 的开始就会执行 RAF 的回调。
    2020-02-18
    7
  • Geek_0d3179
    老师您好~ 在网上搜了一大圈之后还是存在疑惑,非常希望您的解惑~十分感谢! 1、我了解到event loop的流程是:一个macrotask >> UI 渲染 >> 任务队列取下一个macrotask 疑问:每执行一个macrotask后面一定会UI 渲染吗?如果此时DOM和样式并没有改变,根本不需要重新渲染呢?也就是根本不需要回流、重绘和合成。 2、听了老师的讲解后,得知渲染进程在每一帧时间里都会重新绘制,合成一帧图片推到后缓冲区,就算UI没有变化也会执行吗?那这个执行的时机是?是得到VSync信号的时候吗?那这是作为一个宏任务执行的吗? 3、我并没有搞清楚上面1和2的关系。也就是event loop 和 一帧时间的关系。我的理解:在一帧的时间里会不断的从任务队列中取出任务执行,那如果任务队列有太多任务,“重新绘制一帧推到后缓冲区”这个操作会被延迟吗?
    2019-12-03
    3
    7
  • 一七
    https://www.bilibili.com/video/BV1K4411D7Jb?spm_id_from=333.1007.top_right_bar_window_default_collection.content.click 强烈推荐大家看一下这个视频,讲事件循环的
    2022-03-20
    5
  • Trust_
    <html> <head> <title>Main</title> <style> .test { width: 100px; height: 100px; background-color: royalblue; } </style> </head> <body> <button>点击</button> <div class="test"></div> <script> document.querySelector('button').addEventListener('click', () => { const test = document.querySelector('.test'); test.style.transform = 'translate(400px, 0)'; requestAnimationFrame(() => { test.style.transition = 'transform 3s linear'; test.style.transform = 'translate(200px, 0)'; }); }); </script> </body> </html> 这段代码在Chrome执行之后,元素是从右往左移动的,说明是先绘制然后才执行的rAf 在火狐执行之后相反,是从右往左移动的 老师能解答一下吗
    2021-07-05
    3
  • 暖桔灯笼
    老师,在 宏任务与微任务 那一章的讲解中,下面有一个您的回答说在浏览器的实现中目前只实现了一个消息队列和一个延迟队列?这和这里第二次迭代--根据消息类型来实现消息队列 说法是不是冲突?如果确实实现了多个消息队列,会不会跟之前说的"循环系统的一个循环中,先从消息队列头部取出一个任务执行,该任务执行完后,再去延迟队列中找到所有的过期任务依次执行完"有冲突?我现在有点迷惑浏览器到底实现了几个几个消息队列?囧。。。
    2020-05-11
    1
    3
收起评论
显示
设置
留言
33
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部