面试题库 词条目录
前端Wiki/面试题库/JavaScript/JS 进阶题

Promise 与异步编程

Promise 是异步操作的“承诺”:pending → fulfilled / rejected 三态,状态一旦敲定不可逆。then 返回新 Promise,因此可以链式调用;未处理的 rejection 会在事件循环末尾触发 unhandledrejection 事件。

手写 Promise 是高频题,核心是“发布订阅 + then 返回新 Promise”:resolve / reject 把回调存入数组,状态敲定后依次执行。实际项目中常考四个并发 API:Promise.all(全成才 resolve,一个失败即失败)、Promise.race(第一个落定者胜出,不论成败)、Promise.allSettled(等全部落定,结果带 status)、Promise.any(首个成功者,全失败才失败)。

  • 三态不可逆;then 返回新 Promise 实现链式调用
  • all 全成才成功,allSettled 等全部落定,race 看最快,any 看首个成功
  • Promise 本质是回调函数的发布订阅 + 状态机
JS
// 四个并发 API 对比
const p = (name, ms, ok = true) =>
  new Promise((res, rej) => setTimeout(() => (ok ? res(name) : rej(name)), ms));

Promise.all([p('A', 30), p('B', 20)]).then(r => console.log('all:', r));         // [A, B]
Promise.race([p('A', 30), p('B', 20)]).then(r => console.log('race:', r));       // B(最快落定)
Promise.allSettled([p('A', 10), p('B', 20, false)]).then(r => console.log('settled:', r));
Promise.any([p('A', 20, false), p('B', 30)]).then(r => console.log('any:', r));  // B

// 简化版手写 Promise(核心思路)
class MyPromise {
  constructor(executor) {
    this.state = 'pending';
    this.cbs = [];                                  // 订阅:then 的回调
    const settle = (state, val) => {
      if (this.state !== 'pending') return;         // 状态不可逆
      this.state = state; this.value = val;
      this.cbs.forEach(cb => cb());                 // 状态敲定,通知订阅者
    };
    executor(v => settle('fulfilled', v), e => settle('rejected', e));
  }
  then(onOk, onFail) {
    return new MyPromise((res, rej) => {
      const handle = () => {                        // 微任务时机 + 递归 then
        queueMicrotask(() => {
          const fn = this.state === 'fulfilled' ? onOk : onFail;
          try { res(fn(this.value)); } catch (e) { rej(e); }
        });
      };
      this.state === 'pending' ? this.cbs.push(handle) : handle();
    });
  }
}
new MyPromise(r => setTimeout(() => r('手写成功'), 50))
  .then(v => console.log(v));
本节要点Promise = 三态状态机 + 回调订阅;四个并发 API 的差异(all / allSettled / race / any)要一句话说清。