7、✅ 手写 Promise(完整支持 then / resolve / reject / 链式调用)

57 阅读2分钟

🎯 一、为什么要手写 Promise?

面试官想知道你:

  • 是否真正理解异步执行机制、任务队列、Promise 状态机
  • 能否通过状态管理、回调存储等方式还原 Promise 的行为
  • 是否掌握链式调用、微任务执行时机等细节

📌 二、Promise 的核心行为

特性描述
三种状态pending → fulfilled / rejected(不可逆)
then 可链式调用每次 then 都返回新的 Promise
then 异步执行放入微任务队列
支持多个 then同一个 Promise 可以多次注册 then
支持异常穿透then 中出错会走到下一个 reject
then 返回值支持普通值 / Promise / thenable

✍️ 三、最小可运行版本(支持 then/resolve/reject)

class MyPromise {
  constructor(executor) {
    this.state = 'pending';
    this.value = undefined;
    this.reason = undefined;

    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = value => {
      if (this.state === 'pending') {
        queueMicrotask(() => {
          this.state = 'fulfilled';
          this.value = value;
          this.onFulfilledCallbacks.forEach(fn => fn(value));
        });
      }
    };

    const reject = reason => {
      if (this.state === 'pending') {
        queueMicrotask(() => {
          this.state = 'rejected';
          this.reason = reason;
          this.onRejectedCallbacks.forEach(fn => fn(reason));
        });
      }
    };

    try {
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }

  then(onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      const fulfilledFn = value => {
        try {
          const result = onFulfilled ? onFulfilled(value) : value;
          resolve(result);
        } catch (err) {
          reject(err);
        }
      };

      const rejectedFn = reason => {
        try {
          const result = onRejected ? onRejected(reason) : reason;
          reject(result);
        } catch (err) {
          reject(err);
        }
      };

      if (this.state === 'fulfilled') {
        queueMicrotask(() => fulfilledFn(this.value));
      } else if (this.state === 'rejected') {
        queueMicrotask(() => rejectedFn(this.reason));
      } else {
        this.onFulfilledCallbacks.push(fulfilledFn);
        this.onRejectedCallbacks.push(rejectedFn);
      }
    });
  }
}

✅ 四、验证用例

new MyPromise((resolve, reject) => {
  setTimeout(() => resolve('成功'), 1000);
})
.then(res => {
  console.log('第一次', res);
  return '第二次';
})
.then(res => {
  console.log('第二次', res);
});

📌 五、进阶功能建议支持

特性说明
链式调用中的 Promise 嵌套then 的返回值可能是一个 Promise
catch 方法then(null, onRejected)
finally 方法无论成功失败都执行
静态方法 MyPromise.resolve() MyPromise.reject()简化创建
Promise.all / race多 Promise 聚合

🧠 六、状态图理解(推荐画图输出)

       ┌─────────────┐
       │  pending    │
       └────┬────────┘
        resolve | reject
               ↓
     ┌───────────────┐
     │fulfilled/rejected│
     └─────────────────┘

❗ 七、面试陷阱与注意点

问题正确处理
then 执行顺序使用 queueMicrotask 保证异步
then 返回 Promise 怎么处理?调用 resolvePromise(),递归展开
then 中报错会怎样?进入 reject 流程
一个 promise 多次 then?所有回调都会执行