浏览器工作原理——消息队列与事件循环
页面事件循环系统
了解页面到底是如何运行的
了解浏览器的主线程是如何动作的
线程模型(一)—— 主线程依照代码顺序,依次执行任务
用单线程是按顺序,依次处理确定好的任务
1 | var a = 1 + 2; // task1 |
线程模型(二)—— 事件循环机制处理线程执行过程中接收的新任务
线程运行过程中加入新的任务
引入 循环语句 和 事件系统,在线程执行过程中接收并处理新任务。
采用事件循环机制,在线程运行过程中接收并执行新任务
1 | // main thead |
- 主线程中 引入循环机制,即在线程语句加入 for 循环,线程会一直循环执行;
- 引入事件,如在线程运行过程中,等待用户输入,线程暂停,接收到用户输入后,线程激活,继续执行。
线程模型(三)—— 消息队列管理 IO 线程传递的新任务,循环机制从消息队列中取任务执行
引入 消息队列 接收其它线程发送过来的任务。
使用消息队列管理IO线程传递的任务,队列先进行出,任务添加在队列尾部,从头部取出
消息队列是一种数据结构,可以存放要执行的任务。特点先进先出,添加到尾部,从头部取出
1 | // 构造队列 |
其它线程想要发送任务让主线程执行,只需要将任务添加到消息队列中就可以了。由于多个线程操作同一个消息队列,所以在添加任务和取出任务时还会加一个同步锁。
线程模型(四)—— 处理其它进程发送过来的任务
如果其它线程想要发送任务给页面主线程,那么需要先通过 IPC 把任务发送给渲染进程的 IO 线程,IO 线程再把任务发送给页面主线程。
渲染进程专门有一个IO线程用来接收其它线程传进来的消息,IO线程会将这些消息组装成任务发送给渲染主线程
消息队列中的任务类型
事件类型
内部消息类型 |
---|
输入事件(鼠标事件) |
微任务 |
文件读写 |
WebSocket |
javaScript定时器 |
页面相关的事件 |
---|
javaScript 执行 |
解析 DOM |
样式计算 |
布局计算 |
css 动画 |
以上事件是在主线程中执行的,所以在编写 web 应用程序时,需要衡量这些事件所占用的时长、并解决单个任务占用主线程过久的问题。
主线程如何安全退出
chrome 确定退出当前页面时,页面主线程会设置一个退出标志的变量,在每次执行完一个任务时,判断是否设置退出标志。如果有,直接中断所有任务,退出线程。
1 | TaskQueue task_queue |
页面中使用单线程的缺点——微任务解决效率和实时性问题
如何处理高优先级的任务
场景:在处理监听 DOM 节点变化(即 DOM 插入、修改、删除等),根据这些变化处理相应的业务逻辑的场景。
处理方式:通常是采用观察者模式——利用 javaScript
设计监听接口,当变化发生时,渲染引擎同步调用这些接口。
问题:DOM 变化非常频繁,每次变化都调用直接调用相应 javaScript 接口,那么当前任务执行时间拉长,导致执行效率下降。如果将 DOM
变化做成异步消息事件,添加到消息队列尾部,又会影响到监控的实时性。
解决方式:微任务用来权衡实时性与效率,微任务如何权衡效率与实时性的
消息队列中的任务称为宏任务,每个宏任务中都包含一个微任务队列。
在执行宏任务中,DOM 有变化,那么就会将变化添加到微任务列表中,这样就不会影响到宏任务的执行。解决了执行效率问题。
当前宏任务执行完成,执行当前宏任务的微任务(DOM 变化的事件都保存在微任务列表中),从而解决了实时性的问题。
如何解决单个任务执行过久的问题
javaScript 通过回调功能解决单个任务执行过久,造成后面任务等待时间太长,给用户卡顿的感觉。JavaScript 可以通过回调功能来规避,也就是让要执行 JavaScript
任务滞后执行。
浏览器如何运行的
开发者工具 –> performance 标签 –> 右上角 start profiling and load page
我们点击展开了 Main 这个项目,其记录了主线程执行过程中的所有任务。图中灰色的就是一个个任务,每个任务下面还有子任务,其中的 Parse HTML 任务,是把 HTML 解析为 DOM 的任务。值得注意的是,在执行 Parse HTML 的时候,如果遇到 JavaScript 脚本,那么会暂停当前的 HTML 解析而去执行 JavaScript 脚本。
总结
graph TD module1[主线程按顺序依次执行任务]--> module2[主线程引入循环语句与事件系统,处理执行过程中接收的新任务] module2 --> module3[主线程与消息队列解决其它线程发送的任务] module3 --> module4[其它线程通过IPC把任务发送给渲染进程的IO线程,IO线程把任务发送给主线程] module4 --> module5[引入微任务解决效率与实时性问题]