用大白话告诉你什么是Event Loop (2)

我们知道 JavaScript是单线程的,就像上面故事的老板,他得去服务员去招待客人点菜,并将菜单给厨师,厨师炒好后再给到他去上菜。如果老板不请个厨师,自己来炒菜的话,那么在炒菜时就没办法接待客人,客人就会等待点菜。等着等着就会暴露出服务态度不行的问题。所以说,得有厨师专门处理炒菜的任务

所以在js中,任务分为同步任务和异步任务,

同步任务 -> 服务员去接待客人点菜

异步任务 -> 厨师炒菜、异步回调函数相当于 服务员去上菜

image

JS的事件循环如图所示,

在执行主线程的任务时,如果有异步任务,会进入到Event Table并注册回调函数,当指定的事情完成后,会将这个回调函数放到 callback queue

在主线程执行完毕之后,会去读取 callback queue中的回调函数,进入主线程执行

不断的重复这个过程,也就是常说的Event Loop(事件循环)了

2. 异步任务

异步任务又分为宏任务跟微任务、他们之间的区别主要是执行顺序的不同。

在js中,微任务有

原生的Promise -> 其实就是我们上面提到的VIP用户

process.nextTick -> 其实就是我们上面提到的超级VIP用户

process.nextTick的执行优先级高于Promise

宏任务

整体代码 script

setTimeout -> 其实就是我们上面提到的普通用户

setImmediate -> 其实就是我们上面提到的群体用户

setTimeout的执行优先级高于 setImmediate

宏任务与微任务的执行过程

在一次事件循环中,JS会首先执行 整体代码 script,执行完后会去判断微任务队列中是否有微任务,如果有,将它们逐一执行完后在一次执行宏任务。如此流程

image

测试

下面我们来看一段代码是否了解了这个流程

<script> setTimeout(() => { console.log('a'); new Promise( res => { res() }).then( () => { console.log('c'); }) process.nextTick(() => { console.log('h'); }) }, 0) console.log('b'); process.nextTick( () => { console.log('d'); process.nextTick(() => { console.log('e'); process.nextTick(() => { console.log('f'); }) }) }) setImmediate( () => { console.log('g'); }) </script>

执行结果为:b d e f a h c g

让我们来分析一下这段代码的执行流程

首页执行第一个宏任务 整段script标签代码,遇到第一个 setTimeout,将其回调函数加入到任务队列中,

输出 console.log('b')

遇到process.nextTick,将其回调函数加入到任务

遇到setImmediate 将其回调函数加入到任务队列中

宏任务Event Queue 微任务Event Queue
setTimeout   process.nextTick  
setImmediate    

当第一个宏任务执行完后,就会去判断是否还有任务,刚好有一个 任务,执行process.nextTick的回调,输出 console.log('d'),然后又遇到了一个process.nextTick,又将其放入到任务队列

继续将任务队列中的回调函数取出,继续执行,输出 console.log('e'),然后又遇到了一个process.nextTick,又将其放入到任务队列

继续将任务队列中的回调函数取出,继续执行,输出 console.log('f'),然后又遇到了一个process.nextTick,又将其放入到任务队列

宏任务Event Queue 微任务Event Queue
setTimeout    
setImmediate    

当微任务队列为空后,开始新的宏任务,取出第一个宏任务队列的函数,setTimeout,执行 console.log('a'),然后遇到Promise,process.nextTick 将其回调加入到任务队列。执行完后

宏任务Event Queue 微任务Event Queue
setImmediate   promise.then  
-   process.nextTick  

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsswpw.html