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. 微任务阶段 按照微任务队列先进先出顺序:

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

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

面试官考察重点:

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

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