vlambda博客
学习文章列表

弄懂浏览器Event Loop和node的Even Loop的区别

首先,我们来看一下浏览器。


浏览器工作原理



我们今天所讨论的主题就是上图中的那个圈圈(Even Loop)。


让我们一步步来。

浏览器端的 Event Loopq

     一个函数执行栈,一个事件队列(也就是宏任务队列 Macrotask Queue)和一个微任务队列(Microtask Queue)。每次从事件队列中取一个事件时,要是还有微任务就把微任务执行完,然后才开始事件。


弄懂浏览器Event Loop和node的Even Loop的区别


宏任务和微任务

1、宏任务,macrotask,也叫tasks。一些异步任务的回调会依次进入macro task queue,等待后续被调用,这些异步任务包括:


    setTimeout

    setInterval

    setImmediate(Node独有)

    requestAnimationFrame(浏览器独有)

    I/o

    UI rendering(浏览器独有)

2、微任务,microtask,也叫jobs。另外一些异步任务的回调会依次进入micro task queue ,等待后续被调用,这些异步任务包括:

    process.nextTick(node独有)

    Promise.then()

    Object.observer

    MultationObserver


ps:Promise构造函数里面的nn代码是同步执行的。


下面直接来一道题:


弄懂浏览器Event Loop和node的Even Loop的区别


这道题的输出结果为 1 3 2,

解析:上面的两个setTimeout为宏任务,而且是在下一轮事件循环中执行的。在下一轮事件循环中,浏览器先执行了第一个宏任务,打印了 1,然后继续执行下一个宏任务,在这之前,会检查是否还有微任务存在,然后执行微任务。刚好Promise.resolve.then是一个微任务,所以就先执行了,打印出 3,最后执行剩下的宏任务,打印 2。


再来一道稍微难一点的:


弄懂浏览器Event Loop和node的Even Loop的区别


输出结果如下:

弄懂浏览器Event Loop和node的Even Loop的区别

可以看到上面的输出顺序为 3 4 6 8 5 9 2,其中,需要注意的是requestAnimationFrame是一个宏任务,他和setTmeout有点类似,但是却不一样。这里因为setTimeout中定义了一个10毫秒的延迟,所以,9就先输出来了。


浏览器端的Event  Loop小结:

其实主要是包含下三个东西,

一个函数调用栈(用来执行js代码)

一个宏任务队列

一个微任务队列
在event loop调度yyi个宏任务之前,先查看微任务队列中是否还有微任务未执行,如果有,先执行完所有的微任务。


下面来看下node端的


了解一下Node.js的架构图


弄懂浏览器Event Loop和node的Even Loop的区别


这里需要注意的是node的event loop是在libuv里面的,而不是在V8里面,浏览器也是一样。v8主要是解决函数调用栈里面的东西,比如js代码内存空间分配的问题。


node中的Event Loop


弄懂浏览器Event Loop和node的Even Loop的区别


由上图可以看到,node的event loop有6个阶段,其中每个阶段都会有一个对应的宏任务队列。每个阶段都是循环往复的


       每个阶段都会等到该阶段的宏任务队列里面的任务全部执行完,才进行下一阶段的宏任务执行。所以在取任务的时候,node和浏览器不一样,不仅仅是只取出一个,而是多个取出,并执行。  

      而两个宏任务队列之间,会有个间隙,会执行微任务,这一点就和浏览器一样了。


所以Node的Event Loop的过程如下:


    1、执行全局Script的同步代码

    2、执行microtask微任务,先执行所有Next Tick Queue中的所有任务,再执行Other Microtask Queue中的所有任务

    3、开始执行macrotask宏任务,共6个阶段,从第1个阶段开始执行相应每一个阶段macrotask中的所有任务,注意,这里是所有每个阶段宏任务队列的所有任务,在浏览器的Event Loop中是只取宏队列的第一个任务出来执行,每一个阶段的macrotask任务执行完毕后,开始执行微任务,也就是步骤2

    4、Timers Queue -> 步骤2 -> I/O Queue -> 步骤2 -> Check Queue -> 步骤2 -> Close Callback Queue -> 步骤2 -> Timers Queue ......

    5、这就是Node的Event Loop【简化版】

    



总结:

1、浏览器的Event Loop和Node.js 的Event Loop是不同的,实现机制也不一样,不要混为一谈。

2、Node.js 可以理解成有4个(如上图,常用的四个,其他两个是node内部的,我们可以不用太关注)宏任务队列和2个微任务队列,但是执行宏任务时有6个阶段。

3、Node.js 中,先执行全局Script代码,执行完同步代码调用栈清空后,先从微任务队列Next Tick Queue中依次取出所有的任务放入调用栈中执行,再从微任务队列Other Microtask Queue中依次取出所有的任务放入调用栈中执行。然后开始宏任务的6个阶段,每个阶段都将该宏任务队列中的所有任务都取出来执行(注意,这里和浏览器不一样,浏览器只取一个,所以从任务调度的角度上看,nodejs会省时一点),每个宏任务阶段执行完毕后,开始执行微任务,再开始执行下一阶段宏任务,以此构成事件循环。






以上是全部内容,感谢观看!!!