Skip to content

Latest commit

 

History

History
47 lines (26 loc) · 3.78 KB

15 消息队列和事件循环.md

File metadata and controls

47 lines (26 loc) · 3.78 KB

15 | 消息队列和事件循环:页面是怎么“活”起来的?

事件循环

主线程的一次执行: 15 消息队列和事件循环-2023-11-19-13-54-02 但并不是所有的任务都是在执行之前统一安排好的,大部分情况下,新的任务是在线程运行过程中产生的。比如在线程执行过程中,又接收到了一个新的任务要求计算“10+2”。要想在线程运行过程中,能接收并执行新的任务,就需要采用事件循环机制。

15 消息队列和事件循环-2023-11-19-13-56-18

  • 引入循环机制:具体实现方式是在线程语句最后添加了一个 for 循环语句,线程会一直循环执行。
  • 引入事件:可以在线程运行过程中,等待用户输入的数字,等待过程中线程处于暂停状态,一旦接收到用户输入的信息,那么线程会被激活,然后执行相加运算,最后输出结果。

消息队列。

通过上面的机制、浏览器可以持续在执行过程中接受新的任务。 但是目前所有的任务都是来自于主线程内部的,如果另外一个线程如 IO线程 想让主线程执行一个任务就需要通过一种机制来实现,这种机制就是消息队列

15 消息队列和事件循环-2023-11-19-14-03-42

当 IO 线程中产生的新任务时添加进消息队列尾部。渲染主线程会循环地从消息队列头部中读取任务,执行任务。

IO 线程

渲染进程专门有一个 IO 线程用来接收其他进程传进来的消息,接收到消息之后,会将这些消息组装成任务发送给渲染主线程,后续的步骤就和前面讲解的“处理其他线程发送的任务”一样了

15 消息队列和事件循环-2023-11-19-11-51-40

消息队列中的任务类型

消息队列中包含了很多内部消息类型,如输入事件(鼠标滚动、点击、移动)、微任务、文件读写、WebSocket、JavaScript 定时器等等。

此外,消息队列中还包含了很多与页面相关的事件,如 JavaScript 执行、解析 DOM、样式计算、布局计算、CSS 动画等。

处理高优先级的任务。

消息队列是“先进先出”的属性,也就是说放入队列中的任务,需要等待前面的任务被执行完,才会被执行。

然而一些高优先级的任务:如监控 DOM 节点的变化情况(节点的插入、修改、删除等动态变化),然后根据这些变化来处理相应的业务逻辑。

如果每次发生变化的时候,都直接调用相应的 JavaScript 接口,那么这个当前的任务执行时间会被拉长,从而导致执行效率的下降。

如果将这些 DOM 变化做成异步的消息事件,添加到消息队列的尾部,那么又会影响到监控的实时性,因为在添加到消息队列的过程中,可能前面就有很多任务在排队了。

为了权衡效率和实时性,微任务就应用而生了。

通常我们把消息队列中的任务称为宏任务,每个宏任务中都包含了一个微任务队列。 在执行宏任务的过程中,如果 DOM 有变化,那么就会将该变化添加到微任务列表中,这样就不会影响到宏任务的继续执行,因此也就解决了执行效率的问题。

等宏任务中的主要功能都直接完成之后,这时候,渲染引擎并不着急去执行下一个宏任务,而是执行当前宏任务中的微任务。这样就保证了微任务中的 DOM 变化可以及时得到处理,从而保证了实时性。