#develop/Front-End/浏览器原理
每个渲染进程都有一个主线程,但主线程非常繁忙,要同时处理DOM、计算样式、处理布局、JS任务以及各种输入事件,所以需要引入一个系统来统筹调度这些任务,这个系统就是接下来要讨论的消息队列和事件循环系统
我们先从最简单的入手
- 任务1:1+1
- 任务2:2+2
- 任务3:3+3
- 。。。一系列同步任务
- 任务结束
上面的任务都是事先安排好的,但是如果在线程运行中,需要接收并执行新的任务,那么就需要引入事件循环机制了
- 引入循环机制,在线程后添加一个for循环语句,让线程一直循环执行
- 引入事件,把一个任务理解为一个事件,一次for循环可以等待一个事件的执行
如果另外一个线程想要让主线程执行一个任务,以上的模型是做不到的,比如下图
那么我们需要引入消息队列的概念
有了第三版的消息队列模型,实现了主进程下线程之间的消息通信,那再扩大一点,跨进程之间的任务处理也是类似的,在渲染进程中有一个专门的IO线程用来接收其他进程传来的消息,然后组装成任务推进消息队列
- 如何处理高优先级的任务
- 如何解决单个任务执行时间过长的问题
第一个问题,比如监控DOM节点变化,执行业务逻辑 通用方案是JS设计监听接口,渲染引擎同步调用接口,但带来的问题是每次变化时都执行JS接口,当前任务会被无限拉长,执行效率过低;但如果把DOM变化做成异步消息事件,推到消息队列尾部,那么监控的实时性又会降低
如果 DOM 发生变化,采用同步通知的方式,会影响当前任务的执行效率;如果采用异步方式,又会影响到监控的实时性。
这时候微任务就诞生了,把DOM变化的任务推进微任务队列,等当前宏任务执行完后,不是立马去执行下一个宏任务,而是先把当前宏任务下的微任务队列给执行清空,这样就比较合理的兼顾了实时性和效率的问题
但是,如果这个宏任务中存在一个耗时比较长的任务呢,也就是第二个问题,单任务执行过长阻塞,如图所示
比如用JS执行动画,如果某个任务执行时间过长,占用了动画单帧的时间,页面就会卡顿,也就是掉帧,在JS中我们通过滞后该任务,也就是回调的形式,后面再讨论
- 简单同步线程模型,执行事先确认好的同步任务
- 引入循环语句和事件系统,在线程执行中接收并处理新的任务
- 引入消息队列,接收其他线程发送过来的任务
- 由渲染进程的IO线程来接收其他进程通过IPC发送过来的任务,继续沿用消息队列模型
- 为了优化消息队列的效率和实时性问题,引入了微任务