「web浏览器」通过 rAF,聊聊浏览器的任务调度

简介: 本文主要介绍浏览器相关知识点,通过 rAF,了解浏览器的任务调度。

前言

周末在家学习李兵老师的《浏览器工作原理与实践》课程,结尾有六个加餐内容。其中一篇“加餐二|任务调度:有了setTimeOut,为什么还要使用rAF?”引起了我的思维发散。

  • rAF是什么?
  • 为什么rAF可以替代setTimeOut?
  • 浏览器的任务调度是什么?

我总觉得,如果弄懂这几个问题,我对浏览器的工作原理会有质的理解。(可能并不会,试试才知道。)

于是我认真读完老师的文章,还查阅了一些资料,将这块相关的知识点总结了出来。

rAF

rAF是requestAnimationFrame的简写。

MDN的介绍:

window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。

当你准备更新动画时你应该调用此方法。这将使浏览器在下一次重绘之前调用你传入给该方法的动画函数 (即你的回调函数)。回调函数执行次数通常是每秒 60 次。

这样读来确实有点像定时,设置好重绘的延时,循环进行更新。不过,rAF将刷新的频率固定为每秒60帧。

上效果

叶一一感觉最近有点手头紧,所以利用周末的时间,到劳务市场找了一份兼职,帮新房刷墙。

已知一个新房大概10面墙,每面墙 包含13*20 块砖,叶一一每秒能刷60块。叶一一早上8点开始干活,中午12点休息,上午能刷完几面墙?

开完的,不必真的计算(喜欢数学的朋友可以算一算,不过我这里没有答案)。

大概的功能就是,我设计了一个包含 13*20个矩形的图案,使用rAF设置动画进行颜色设置,每秒刷新60个色块,实现如下,点击刷墙即可开启动画效果。

在线预览


rAF和setTimeOut

这是什么组合?为什么会有rAF替代setTimeOut的说法?

说一段历史

其实就是原本动画使用setTimeOut定时去实现更新。浏览器供应商一合计,使用者每次用代码实现一遍定时功能多麻烦,为什么我们不提供一个API,我们还能为使用者优化一些东西。

于是rAF应用而生,它是用于动画的基本 API,无论是基于 DOM 的样式更改、画布还是 WebGL。

setTimeOut的表现

我感觉我可能遗漏了setTimeout的特别信息,于是我到MDN文档里,认真阅读了它的知识点,果然,在备注里找到了几条注意事项:

  • 当前页面(或者操作系统/浏览器本身)被其他任务占用时,会导致定时器延时;
  • 最小延时 >=4ms,在浏览器中,函数嵌套,或者是由于已经执行的 setInterval 的回调函数阻塞,那么setTimeout每调用一次定时器的最小间隔是 4ms;
  • 未被激活的页面,定时最小延迟>=1000ms,主要是为了优化后台页面的加载损耗
  • 有最大值延时值。

我摸了摸下巴,好像明白了setTimeout定时导致页面卡顿的原因。

我还在张鑫旭大神的文章《CSS3动画那么强,requestAnimationFrame还有毛线用?》一文中找到了一个有趣的表格,关于页面处于闲置的时候,不同浏览器对于setTimeOut和rAF两个方式,设置定时间隔的表现:

浏览器

setInterval

requestAnimationFrame

IE

无影响

暂停

Safari

无影响

暂停

Firefox

>=1s

1s - 3s

Chrome

>=1s

暂停

Opera

无影响

暂停

rAF的表现

大佬的《requestAnimationFrame for Smart Animating》一文中是这样概括的:

  • 浏览器可以优化,所以动画会更流畅;
  • 非活动页面中的动画将停止,让 CPU 冷却;
  • 对电池更友好。

仔细想想也是,浏览器供应商提供的支持性质的API,会针对当下的一些浏览器问题,做出优化。

取而代之

经过上面的一系列知识点陈列之后,结论也就来了。

rAF替代setTimeOut做动画定时重绘,基于几点:

  • 并发动画优化为单个回流和重绘循环,从而获得更高保真度的动画
  • 非活动页面动画停止,更少的 CPU、GPU 和内存使用,从而延长电池寿命

任务调度

重头戏来了,往往不常用的功能,尤其是原理的知识,比较难理解。这次也不例外,我将李兵老师的文章知识点整理加上一些个人理解汇总了下来。以下内容算是一个学习笔记吧。

任务调度是什么以及它是怎么工作的呢?这一切要先从事件循环系统说起。

消息循环系统

每个渲染进程都有一个主线程,当主线程忙着处理DOM,忙着计算重绘,忙着处理JS事件的时候,就需要一个系统帮忙排班了。这个系统就是消息循环系统。

工作内容

消息循环系统的工作内容具体是什么呢?

李兵老师做了以下总结:

  • 使用单线程处理安排好的任务;
  • 在线程运行过程中处理新任务;
  • 处理其他线程发送过来的任务;
  • 处理其他进程发送过来的任务。

安全退出

活干完的时候,怎么保证页面主线程能够安全退出呢?

Chrome是这样干的,页面主线程会设置一个退出标志的变量,在每次执行完一个任务时,根据这个退出标志判断是否退出。

小结

1、明确的任务,排好序,可以用单线程来按顺序处理;

2、在线程运行过程中,可以采用事件循环机制接收并处理新任务;

3、其他线程发送过来的任务,为了确定任务的执行顺序,采用消息队列的方式;

4、单消息队列,存在着低优先级任务会阻塞高优先级任务的情况。

小结中的前三项,都是采用什么策略解决什么问题,最后一个问题,只有问题内容,没有解决方案,如何解决任务优先级的问题呢?

这个问题就引出了今天的主要内容——任务调度。

单消息队列的队头阻塞问题

问题描述

渲主线程会按照先进先出的顺序执行消息队列中的任务,当需要处理的任务逐渐增多时,对应进程的主线程也变得越拥挤,于是就出现了低优先级任务会阻塞高优先级任务的情况,把这种情况称之为消息队列的队头阻塞问题。

Chromium 是如何解决队头阻塞问题

这里通过李兵老师参考Chromium 团队的解决方案,分析如何解决队头阻塞的问题,我将重点内容进行了抽离。

第一次迭代:引入一个高优先级队列

在渲染进程中引入一个任务调度器,负责从多个消息队列中选出合适的任务,通常实现的逻辑,先按照顺序从高优先级队列中取出任务,如果高优先级的队列为空,那么再按照顺序从低优级队列中取出任务。

结合任务调度器灵活地调度任务,可以让高优先级的任务提前执行,采用这种方式似乎解决了消息队列的队头阻塞问题。

但是高优先级的确认是分情况的,更多的时候需要保持其相对执行顺序,如果将用户输入的消息或者合成消息添加进多个不同优先级的队列中,那么这种任务的相对执行顺序就会被打乱,甚至前置事件还没完成后置事件就已经执行了。因此需要让一些相同类型的任务保持其相对执行顺序。

第二次迭代:根据消息类型来实现消息队列

解决上面提到问题,可以为不同类型的任务创建不同优先级的消息队列。也就是说根据消息类型来创建消息队列。

但是它的问题是,消息队列的优先级都是固定的,任务调度器会按照固定好的静态的优先级来分别调度任务。但是静态的优先级会导致新的问题。

在页面加载阶段,使用静态优先级策略,可能会导致页面的解析速度将会被拖慢。

第三次迭代:动态调度策略

既然静态优先级策略有短板,那么动态调整策略怎么样呢?

动态调整策略主要是在页面不同的生存周期阶段,采用不同的优先策略。

页面大致的生存周期大体分为两个阶段,加载阶段和交互阶段。

来看Chromium 在不同的场景下,是如何调整消息队列优先级的

这样的优先级策略更为合理。

第四次迭代:任务饿死

以上方案看上去似乎非常完美了,不过依然存在一个问题,那就是在某个状态下,一直有新的高优先级的任务加入到队列中,这样就会导致其他低优先级的任务得不到执行,这称为任务饿死。

Chromium 为了解决任务饿死的问题,给每个队列设置了执行权重,也就是如果连续执行了一定个数的高优先级的任务,那么中间会执行一次低优先级的任务,这样就缓解了任务饿死的情况。

总结

今天的学习清单有点分量:

  • rAF是浏览器供应商提供的API,功能是实现逐帧动画,并尝试如何使用它设置动画;
  • 理清了rAF可以setTimeOut的原因在于保持高保真度的动画和提升电池寿命;
  • 单消息队列的队头阻塞问题的每一个解决方案中,采用不同的任务调度策略,更为合理的策略是动态调度测试配合解决任务饿死。

今天也是超值的一天。

文章里面可能有一些错误,因为阅读资料的时候,这块的文字实在是太多了。欢迎大家指出,感谢💐。

目录
相关文章
|
3月前
|
Web App开发 iOS开发
Web 浏览器
【8月更文挑战第27天】Web 浏览器。
57 2
|
2天前
|
人工智能 前端开发 计算机视觉
Inpaint-Web:纯浏览器端实现的开源图像处理工具
在刷短视频时,常看到情侣在景区拍照被路人“抢镜”,男朋友用手机将路人“P”掉,既贴心又有趣。最近我发现了一个纯前端实现的开源项目——inpaint-web,可在浏览器端删除照片中的部分内容,非常酷。该项目基于 WebGPU 和 WASM 技术,支持图像修复与放大,已在 GitHub 上获得 5.1k Star。项目地址:[GitHub](https://github.com/lxfater/inpaint-web)。
40 3
 Inpaint-Web:纯浏览器端实现的开源图像处理工具
|
1月前
|
Web App开发 XML JavaScript
Python 操作浏览器:让 Python 和 Web 世界合二为一
Python 操作浏览器:让 Python 和 Web 世界合二为一
|
6月前
|
存储 搜索推荐 安全
Cookie 探秘:了解 Web 浏览器中的小甜饼
Cookie 探秘:了解 Web 浏览器中的小甜饼
|
3月前
|
机器学习/深度学习 存储 前端开发
实战揭秘:如何借助TensorFlow.js的强大力量,轻松将高效能的机器学习模型无缝集成到Web浏览器中,从而打造智能化的前端应用并优化用户体验
【8月更文挑战第31天】将机器学习模型集成到Web应用中,可让用户在浏览器内体验智能化功能。TensorFlow.js作为在客户端浏览器中运行的库,提供了强大支持。本文通过问答形式详细介绍如何使用TensorFlow.js将机器学习模型带入Web浏览器,并通过具体示例代码展示最佳实践。首先,需在HTML文件中引入TensorFlow.js库;接着,可通过加载预训练模型如MobileNet实现图像分类;然后,编写代码处理图像识别并显示结果;此外,还介绍了如何训练自定义模型及优化模型性能的方法,包括模型量化、剪枝和压缩等。
50 1
|
3月前
|
API UED 开发者
如何在Uno Platform中轻松实现流畅动画效果——从基础到优化,全方位打造用户友好的动态交互体验!
【8月更文挑战第31天】在开发跨平台应用时,确保用户界面流畅且具吸引力至关重要。Uno Platform 作为多端统一的开发框架,不仅支持跨系统应用开发,还能通过优化实现流畅动画,增强用户体验。本文探讨了Uno Platform中实现流畅动画的多个方面,包括动画基础、性能优化、实践技巧及问题排查,帮助开发者掌握具体优化策略,提升应用质量与用户满意度。通过合理利用故事板、减少布局复杂性、使用硬件加速等技术,结合异步方法与预设缓存技巧,开发者能够创建美观且流畅的动画效果。
79 0
|
4月前
|
机器人 Shell 开发者
`roslibpy`是一个Python库,它允许非ROS(Robot Operating System)环境(如Web浏览器、移动应用等)与ROS环境进行交互。通过使用`roslibpy`,开发者可以编写Python代码来远程控制ROS节点,发布和订阅话题,以及调用服务。
`roslibpy`是一个Python库,它允许非ROS(Robot Operating System)环境(如Web浏览器、移动应用等)与ROS环境进行交互。通过使用`roslibpy`,开发者可以编写Python代码来远程控制ROS节点,发布和订阅话题,以及调用服务。
|
3月前
|
网络安全 数据安全/隐私保护 iOS开发
【Mac os】如何在服务器上启动Jupyter notebook并在本地浏览器Web端环境编辑程序
本文介绍了如何在服务器上启动Jupyter Notebook并通过SSH隧道在本地浏览器中访问和编辑程序的详细步骤,包括服务器端Jupyter的启动命令、本地终端的SSH隧道建立方法以及在浏览器中访问Jupyter Notebook的流程。
137 0
|
3月前
|
存储 移动开发 编解码
一文读懂Web Codecs API:浏览器背后的媒体魔术师
一文读懂Web Codecs API:浏览器背后的媒体魔术师
40 0
|
5月前
|
数据采集 Web App开发 前端开发
Selenium:自动化Web浏览器操作的强大工具
**Selenium** 是一款用于自动化Web应用测试和模拟用户行为的工具,支持多种浏览器和编程语言。安装包括安装Selenium库和对应浏览器的WebDriver。基本用法包括导入库、启动浏览器、查找与操作页面元素、等待元素加载及关闭浏览器。在实际项目中,Selenium常用于Web测试、爬虫、自动化表单填写等,优点是跨平台、模拟真实用户行为,但性能较低且依赖浏览器。
214 9