EventLoop理解
不多说,大家先看一段代码
1 | |
请问这段代码的打印顺序是什么
正确的答案是:script start, script end, promise1, promise2, setTimeout。
为什么会这样
这就要引出事件循环了。可以看到,上面的代码中有几种任务种类,有setTimeout、Promise和可立即执行的script代码,事件循环可以理解为是一种规范,规定我们单线程的JavaScript以何种顺序去执行js脚本。
在JavaScript中,任务被分为两种,一种宏任务(MacroTask)也叫Task,一种叫微任务(MicroTask)。这两种任务有各自的执行队列。
先来几个概念:
- Tasks:任务,有的地方称为MacroTask(宏任务),以下几类任务被执行时会进入此队列:
script代码、计时器(setTimeout、setInterval、setImmediate)、I/O、UI Rendering。 - MicroTask:微任务,以下几类任务被执行时会进入此队列:
Process.nextTick(Node)、Promise、Object.observe、MutationObserver
分清楚以后,再说一下这两条队列的执行逻辑。一段代码开始执行总会先执行一个Task队列中的第一任务,在上例中,第一个Task是整个script代码,也就是说,代码开始执行时,将全部script代码放入Task队列中,JavaScript开始执行其中的代码。遇到同步任务时,如console.log(),JavaScript会将他放入执行栈,立即执行。遇到异步任务时,先不管他,让他自己执行,执行完毕后,该任务会向任务队列发出信号,根据他的任务类型,放入不同的队列,以便执行后续的回调函数。如setTimeout在0s后向Task队列发出信号,将setTimeout的回调函数放入Task队列中,位置在script代码之后。遇到promise时,同样先让他自己执行,当他执行完毕,向MicroTask队列发出信号,将他的回调函数放入Microtask队列。
当第一个Task,即script全部代码执行完毕后,会先执行所有MicroTask队列中的任务,执行的逻辑与之前相同,遇到同步代码立即执行,异步代码待自行完成后,将各自回调函数加入相应队列。
当所有微任务完成后,JavaScript才会执行Task队列中的下个任务,即setTimeout的回调函数console.log('setTimeout');,以此往复循环(Event Loop)。
下面是示例代码运行的动图
再来几个题,来巩固一下
题目:写出运行结果
1 | |
解析
1 | |
题目:写出运行结果
1 | |
解析
1 | |
题目:写出运行结果
1 | |
解析
1 | |
参考文献
https://juejin.im/post/5cf7857ff265da1bac4005b2
https://hongfanqie.github.io/tasks-microtasks-queues-and-schedules/
https://zhuanlan.zhihu.com/p/55511602
