Skip to content

Promise 面试题 ​

一、最难的 Promise 面试题 ​

Promise 相关面试题中,难度较高的通常考察对异步流程、事件循环的深刻理解和灵活的运用能力。以下是一个经典且具有一定难度的面试题:

题目: ​

请描述以下代码的输出结果及原因:

javascript
console.log("start");

new Promise((resolve, reject) => {
  console.log("promise1");
  resolve();
})
  .then(() => {
    console.log("then1");
    return Promise.resolve();
  })
  .then(() => {
    console.log("then2");
  });

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

console.log("end");

正确答案: ​

输出顺序为:

start
promise1
end
then1
then2
timeout

原因解释: ​

  1. JavaScript 中执行顺序为同步代码优先执行,异步代码后执行。
  2. 首先,console.log('start') 输出 "start"。
  3. 执行 new Promise() 中构造函数里的同步代码,输出 "promise1"。
  4. resolve() 被调用,Promise 状态为 fulfilled,此时 then 方法回调被放入微任务队列等待执行。
  5. setTimeout() 中的回调被放入宏任务队列。
  6. 执行最后一个同步语句 console.log('end'),输出 "end"。
  7. 同步代码执行完成,开始执行微任务,依次输出 "then1" 和 "then2"。
  8. 微任务执行完成,开始执行宏任务,最后输出 "timeout"。

面试考察重点:

  • Promise 状态及 then 链的执行顺序
  • 微任务与宏任务队列执行机制
  • JavaScript Event Loop 工作原理

面试官往往会以这种问题检测候选人对异步、事件循环的精确理解。

二、变种 ​

这里给出一个较为复杂的、Promise 面试题的变种版本:

题目: ​

请描述下面代码的输出结果及原因:

javascript
console.log("script start");

setTimeout(function () {
  console.log("setTimeout");
}, 0);

Promise.resolve()
  .then(function () {
    console.log("promise1");
  })
  .then(function () {
    console.log("promise2");
  });

async function async1() {
  console.log("async1 start");
  await async2();
  console.log("async1 end");
}

async function async2() {
  console.log("async2");
}

async1();

console.log("script end");

正确答案: ​

代码输出结果为:

script start
async1 start
async2
script end
promise1
async1 end
promise2
setTimeout

原因分析: ​

JavaScript 的执行机制(同步代码 → 微任务 → 宏任务):

  1. 同步执行

    • 首先执行 console.log('script start') 输出 script start。

    • 然后遇到 setTimeout 将其回调放入宏任务队列中。

    • 遇到 Promise.resolve().then(...),then 回调进入微任务队列。

    • 执行函数 async1():

      • 输出 async1 start。

      • 调用 async2():

        • 输出 async2。
      • 遇到 await async2() 时,await 后面表达式是立即完成(因为 async2 已执行完),但 JS 会将后续的代码放到微任务队列中。

    • 执行 console.log('script end') 输出 script end。

  2. 微任务阶段 按照微任务队列先进先出顺序:

    • 首先输出 promise1(Promise.resolve().then 回调)。
    • 然后执行之前 await 后面的语句,输出 async1 end。
    • 接着执行链式的第二个 .then,输出 promise2。
  3. 宏任务阶段

    • 最后执行宏任务队列里的 setTimeout,输出 setTimeout。

面试官考察重点: ​

  • async/await 与 Promise 在事件循环中的关系。
  • 微任务与宏任务的执行顺序与差异。
  • await 后面的表达式如果立即 resolve,后续代码进入微任务队列。

这类问题体现了候选人是否真正深入理解 JavaScript 异步运行的内在逻辑。