一段代码理解浏览器和服务端中的Event Loop

Posted 笔记本涂鸦

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一段代码理解浏览器和服务端中的Event Loop相关的知识,希望对你有一定的参考价值。


javascript中的 Event Loop 概念是其核心,也是不同于其他编程语言的关键部分。由于浏览器和服务端运行环境等各方面都存在差异,我们对 Event Loop 机制的理解也应该根据运行环境而有所不同。如果你对JavaScript中的 宏任务 和微任务还不熟悉,可以先跳到文章的最后一部分。下面我们通过一段代码来理解其中的区别。

setTimeout(() => {    
   console.log('setTimeout 1');    Promise.resolve().then(() => {        
       console.log('Promise 1');    });    setTimeout(() => {        
       console.log('setTimeout 4');    }) }) setTimeout(() => {    
   console.log('setTimeout 2');    Promise.resolve().then(() => {        
       console.log('Promise 2');    }).then(() => {        
       console.log('Promise 2-2');    });    setTimeout(() => {        
       console.log('setTimeout 5');    }) }) setTimeout(() => {    
   console.log('setTimeout 3'); })

Promise 的 then 方法的实现机制我们规定为是 微任务 机制,但不排除使用 宏任务 机制实现的运行环境。

使用 node 命令行运行输出结果如下:

//node app.js
setTimeout 1    
setTimeout 2    
setTimeout 3    
Promise 1    
Promise 2    
Promise 2-2    
setTimeout 4    
setTimeout 5

使用 Chrome 浏览器的控制台运行输出结果如下:

//chrome console 控制台
setTimeout 1
Promise 1
setTimeout 2
Promise 2
Promise 2-2
setTimeout 3
setTimeout 4
setTimeout 5

浏览器端:

  1. 从当前宏任务队列中取出 一个 宏任务开始执行;

  2. 下一步开始执行 微任务 队列中的所有任务;

  3. 最后根据浏览器自身策略决定是否需要更新UI(更新阶段处于当前 Loop 中的所有微任务执行完成)。

服务端:

  1. 开始执行当前宏任务队列中的所有任务,直到为空;

  2. 下一步开始执行 微任务 队列中的所有任务;

  3. 开始下一遍循环。


task(宏任务)和 microtask (微任务)的介绍

浏览器端的相关说明:

Tasks are scheduled so the browser can get from its internals into JavaScript/DOM land and ensures these actions happen sequentially. Between tasks, the browser may render updates. Getting from a mouse click to an event callback requires scheduling a task, as does parsing html.

大致意思是:浏览器可以通过 宏任务Tasks 进入到 JS/DOM的内部,并保证任务操作执行顺序。两个 Tasks 任务之间(微任务结束之后渲染),浏览器可以决定渲染更新。

Microtasks are usually scheduled for things that should happen straight after the currently executing script, such as reacting to a batch of actions, or to make something async without taking the penalty of a whole new task. The microtask queue is processed after callbacks as long as no other JavaScript is mid-execution, and at the end of each task. Any additional microtasks queued during microtasks are added to the end of the queue and also processed. Microtasks include mutation observer callbacks, and as in the above example, promise callbacks.

大致意思是:微任务在当前正在执行的脚本后直接发生。微任务发生在回调且在 宏任务 的最后阶段。允许添加新的微任务,并能够及时执行。mutation observer 和 Promise 都属于微任务。

服务端的相关说明:

根据Node.js 官网说明,下图是服务端代码执行的 6 个阶段,每个阶段都有对应的微任务执行,所有阶段形成一个 Event Loop。



一般做如下记忆:

宏任务:

整个脚本,setTimeout,setInterval,setImmediate, I/O,UI rendering。

微任务:

process.nextTick(最先执行), Promise,Object.observer, MutationObserver。


以上是关于一段代码理解浏览器和服务端中的Event Loop的主要内容,如果未能解决你的问题,请参考以下文章

浏览器的 Event Loop

深入理解Javascript单线程谈Event Loop

深入理解javascript中的事件循环event-loop

Diary如何用 Event Loop 理解异步

浅析JS的Event Loop机制

浏览器中的event loop, 简单了解。