🎯 一、为什么要手写 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? | 所有回调都会执行 |