返回

解开 JavaScript 事件循环机制之谜,探寻 Promise面试题背后的真相

前端

在 JavaScript 的面试中,经常会遇到有关事件循环机制的问题,其中一个经典的题目就是Promise面试题。这道题目的本质是考察你对JavaScript事件循环机制的理解,以及你是否能够灵活运用Promise来解决异步编程中的问题。

这道题目通常会给出这样一个场景:

console.log('script start');

setTimeout(() => {
  console.log('setTimeout');
}, 0);

Promise.resolve().then(() => {
  console.log('promise1');
});

Promise.resolve().then(() => {
  console.log('promise2');
});

console.log('script end');

然后让你预测一下,以上代码的输出顺序是什么。

如果你已经对 JavaScript 的事件循环机制有所了解,那么你可能会猜到正确的输出顺序是:

script start
promise1
promise2
setTimeout
script end

但是,如果你对事件循环机制的理解还不够深入,你可能会得出错误的结论。

为了帮助你理解这道题目的本质,我们先来简单回顾一下 JavaScript 的事件循环机制。

事件循环机制

JavaScript的事件循环机制是一个消息队列,它将要执行的任务存储在队列中,然后依次执行它们。

事件循环机制主要分为以下几个步骤:

  1. 首先,JavaScript引擎会执行所有的同步任务,也就是那些没有回调函数的任务。
  2. 当所有同步任务执行完毕后,JavaScript引擎会检查消息队列中是否有任务需要执行。如果有,则取出队列中的第一个任务并执行它。
  3. 当任务执行完毕后,JavaScript引擎会继续检查消息队列中是否有任务需要执行。如果还有,则取出队列中的第一个任务并执行它。
  4. 重复步骤2和步骤3,直到消息队列中没有任务需要执行为止。

Promise面试题的解答

现在,我们回到Promise面试题。

首先,JavaScript引擎会执行所有的同步任务,也就是那些没有回调函数的任务。在这个例子中,只有console.log('script start')是同步任务,因此它会首先执行。

然后,JavaScript引擎会检查消息队列中是否有任务需要执行。在这个例子中,有三个任务在消息队列中等待执行:

  • setTimeout任务
  • Promise.resolve().then(() => { console.log('promise1'); })任务
  • Promise.resolve().then(() => { console.log('promise2'); })任务

由于setTimeout任务的延迟时间为0,因此它会先于其他两个任务执行。

setTimeout任务执行完毕后,JavaScript引擎会再次检查消息队列中是否有任务需要执行。此时,两个Promise任务都已就绪,因此它们会按照先进先出的原则依次执行。

最后,JavaScript引擎会执行console.log('script end')这个同步任务。

因此,整个代码的输出顺序就是:

script start
promise1
promise2
setTimeout
script end

结语

通过这道Promise面试题,我们可以看到,JavaScript的事件循环机制是一个非常重要的知识点,它不仅可以帮助我们理解JavaScript的异步编程模型,而且还可以帮助我们解决一些棘手的面试题。