一道面试题,简单理解event loop,题如下:说说执行过程以及为什么。
Promise.resolve().then(() => {
console.log('promise1');
const timer2 = setTimeout(() => {
console.log('timer2')
}, 0)
});
const timer1 = setTimeout(() => {
console.log('timer1')
Promise.resolve().then(() => {
console.log('promise2')
})
}, 0)
console.log('start');
想象JavaScript的执行环境是一个大型的游乐场,里面有两个区域:一个是“同步游乐区”,另一个是“异步等待区”。在“异步等待区”里,又分为“宏任务游乐场”和“微任务小卖部”。
-
进入游乐场(代码开始执行) :
- 你首先来到“同步游乐区”,看到第一个项目是
console.log('start');,你立即执行它,打印出“start”。
- 你首先来到“同步游乐区”,看到第一个项目是
-
遇到宏任务(setTimeout) :
- 你接着遇到了两个宏任务(
timer1和timer2的setTimeout),但它们不是立即执行的,而是被放在了“宏任务游乐场”的等待队列里。尽管它们都被设置为0毫秒后执行,但JavaScript不会让它们打断当前的同步代码执行。
- 你接着遇到了两个宏任务(
-
遇到微任务(Promise.then) :
- 然后你遇到了一个
Promise.resolve().then(...),这是一个微任务。微任务就像是“微任务小卖部”里的任务,它们会在当前同步代码执行完毕后,且在下一个宏任务之前被处理。所以,你先把这个then的回调函数放在了“微任务小卖部”的队列里。 - 当你完成所有同步代码(即“同步游乐区”的所有项目)后,你首先去“微任务小卖部”查看是否有任务需要执行。你找到了那个
then的回调函数,执行它,打印出“promise1”。 - 在这个
then的回调函数里,你又遇到了一个setTimeout(timer2),同样地,它被放在了“宏任务游乐场”的等待队列里。
- 然后你遇到了一个
-
执行宏任务:
- 完成了“微任务小卖部”的所有任务后,你回到“宏任务游乐场”,看到
timer1的回调已经在队列里了。你执行它,打印出“timer1”。 - 在
timer1的回调里,你又遇到了一个Promise.resolve().then(...),它的回调函数再次被放在了“微任务小卖部”的队列里。
- 完成了“微任务小卖部”的所有任务后,你回到“宏任务游乐场”,看到
-
再次执行微任务:
- 执行完
timer1的回调后,你再次去“微任务小卖部”查看,找到了那个新的then的回调函数,执行它,打印出“promise2”。
- 执行完
-
执行剩余的宏任务:
- 最后,你回到“宏任务游乐场”,看到
timer2的回调也已经在队列里了。你执行它,打印出“timer2”。
- 最后,你回到“宏任务游乐场”,看到
所以,整个执行顺序就是:
start
promise1
timer1
promise2
timer2
图解如下: