从浏览器中的Event Loop(事件循环)机制探索JavaScript异步

Event Loop不同的实现

事件(event):事件就是由于某种外在或内在的信息状态发生的变化,从而导致出现了对应的反应。
比如说用户点击了一个按钮,就是一个事件;HTML页面完成加载,也是一个事件。
而且一个事件中会包含多个任务。

①浏览器在HTML Standard中定义了Event Loop
②Node.js使用了libuv库来实现Event Loop(本人完全不懂Node,用的是Python)

浏览器的Event Loop和Node.js的Event Loop是两个概念,本文只描述基于浏览器的Event Loop

JavaScript中,任务被分为Task(又称为MacroTask,宏任务)和MicroTask(微任务)两种

MacroTask:

MacroTask任务源非常宽泛,总结来说task任务源:
①setTimeout
②setInterval
③I/O
④UI rendering
⑤script
⑥setImmediate(Node.js API)

每一个event loop有一个或者多个task队列。
当用户代理安排一个任务,必须将该任务增加到相应的event loop的一个tsak队列中。
比如可以为鼠标、键盘事件提供一个task队列,其他事件又是一个单独的队列。

注:task也被称为MacroTask,由指定的任务源去提供任务

MicroTask:

HTML Standard没有具体指明哪些是MicroTask任务源,通常认为是MicroTask任务源有:
①promises
②MutationObserver MutationObserver API
③process.nextTick(Node.js API)
④Object.observe(已废弃)

在Promises / A +规范的Notes 3.1中提及了promise的then方法可以采用“宏任务”机制或者‘微任务’机制来实现。所以在不同浏览器的差异正源于此,有的浏览器将then放入了宏任务队列,有的放入了微任务队列

每一个event loop有一个且只有一个microtask队列

注:microtask 队列和task 队列有些相似,由指定的任务源去提供任务;

Event Loop的处理过程(Processing model)

在HTML Standard中Processing model 定义了event loop的循环过程:

一个event loop只要存在,就会不断执行下边的步骤:
1.在tasks队列中选择最先进入的task(!!!参考最下面的思考题),用户代理可以选择任何task队列,如果没有要选择的任务,则跳到下边的microtasks步骤。
2.将上边选择的task设置为currently running task。
3.Run: 运行被选择的task。
4.将event loop的currently running task设置回null。
5.从task队列中移除已经完成运行的task。
6.Microtasks: 执行microtasks checkpoint。(也就是执行microtasks队列里的任务 )
7.更新渲染(Update the rendering)...
8.返回到第一步。

event loop会不断循环上面的步骤,概括说来:
1.event loop会不断循环的去取tasks队列中最老的一个任务推入栈中执行,并在当次循环里依次执行并清空microtask队列里的任务。
2.执行完microtask队列里的任务,有可能会渲染更新。(浏览器很聪明,在一帧以内的多次dom变动浏览器不会立即响应,而是会积攒变动以最高60HZ的频率更新视图)

执行进入microtask检查点时,用户代理会执行以下步骤:

1.将microtask checkpoint的flag设为true。
2.Microtask queue handling: 如果event loop的microtask队列为空,直接跳到第8步(Done)。
3.在microtask队列中选择最先进入队列的一个任务。
4.将上边选择的microtask设为event loop的currently running task。
5.运行被选择的任务。
6.将event loop的currently running task设置回null。
7.从microtask队列中移除已经完成运行的microtask,然后返回到第2步(Microtask queue handling)。
8.Done: 每一个environment settings object它们的 responsible event loop就是当前的event loop,会给environment settings object发一个 rejected promises 的通知。
9.清理IndexedDB的事务。
10.将microtask checkpoint的flag设为flase。

microtask checkpoint所做的就是执行microtask队列里的任务。什么时候会调用microtask checkpoint呢?
1.当上下文执行栈为空时,执行一个microtask checkpoint。
2.在event loop的第六步(Microtasks: Perform a microtask checkpoint)执行checkpoint,也就是在运行task之后,更新渲染之前。

示例

从浏览器中的Event Loop(事件循环)机制探索JavaScript异步_第1张图片

HTML Standard 8.1.4 Event loops

An event loop has one or more task queues. A task queue is an ordered list of tasks, which are algorithms that are responsible for such work as:
Parsing
The HTML parser tokenizing one or more bytes, and then processing any resulting tokens, is typically a task.
Callbacks
Calling a callback is often done by a dedicated task.
译:
事件循环具有一个或多个任务队列。任务队列是一个有序的任务列表,这些算法负责以下工作:
解析
HTML解析器标记一个或多个字节,然后处理任何生成的标记,是典型的一项任务(即我们解析和执行完
                    
                    

你可能感兴趣的:(JS)