Promise 实现-详细
从零开始手写一个符合 Promise/A+ 规范的 Promise 实现,理解 Promise 的原理和异步处理机制
问题
Promise 是 JavaScript 中处理异步操作的重要机制。本题要求手写一个完整的 Promise 实现,需要满足以下要求:
- 实现 Promise 的三种状态:pending、fulfilled、rejected
- 实现 then 方法,支持链式调用
- 实现 catch、finally 方法
- 实现静态方法:resolve、reject、all、race、allSettled、any
- 符合 Promise/A+ 规范
解答
// Promise 的三种状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise {
constructor(executor) {
this.state = PENDING; // 初始状态
this.value = undefined; // 成功的值
this.reason = undefined; // 失败的原因
this.onFulfilledCallbacks = []; // 成功回调队列
this.onRejectedCallbacks = []; // 失败回调队列
// 成功时调用
const resolve = (value) => {
// 只有 pending 状态才能转换
if (this.state === PENDING) {
this.state = FULFILLED;
this.value = value;
// 执行所有成功回调
this.onFulfilledCallbacks.forEach(fn => fn());
}
};
// 失败时调用
const reject = (reason) => {
// 只有 pending 状态才能转换
if (this.state === PENDING) {
this.state = REJECTED;
this.reason = reason;
// 执行所有失败回调
this.onRejectedCallbacks.forEach(fn => fn());
}
};
// 立即执行 executor
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
// then 方法
then(onFulfilled, onRejected) {
// 参数可选,提供默认值
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
// 返回新的 Promise 实现链式调用
const promise2 = new MyPromise((resolve, reject) => {
if (this.state === FULFILLED) {
// 使用 setTimeout 模拟微任务
setTimeout(() => {
try {
const x = onFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
if (this.state === REJECTED) {
setTimeout(() => {
try {
const x = onRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
if (this.state === PENDING) {
// 异步情况,将回调存入队列
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
return promise2;
}
// 处理 then 返回值
resolvePromise(promise2, x, resolve, reject) {
// 不能返回自身,避免循环引用
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected'));
}
// 如果 x 是 Promise 实例
if (x instanceof MyPromise) {
x.then(resolve, reject);
} else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
// 如果 x 是对象或函数
let called = false; // 防止多次调用
try {
const then = x.then;
if (typeof then === 'function') {
// x 是 thenable 对象
then.call(
x,
y => {
if (called) return;
called = true;
this.resolvePromise(promise2, y, resolve, reject);
},
r => {
if (called) return;
called = true;
reject(r);
}
);
} else {
resolve(x);
}
} catch (error) {
if (called) return;
called = true;
reject(error);
}
} else {
// 普通值直接 resolve
resolve(x);
}
}
// catch 方法
catch(onRejected) {
return this.then(null, onRejected);
}
// finally 方法
finally(callback) {
return this.then(
value => MyPromise.resolve(callback()).then(() => value),
reason => MyPromise.resolve(callback()).then(() => { throw reason })
);
}
// 静态 resolve 方法
static resolve(value) {
if (value instanceof MyPromise) {
return value;
}
return new MyPromise(resolve => resolve(value));
}
// 静态 reject 方法
static reject(reason) {
return new MyPromise((resolve, reject) => reject(reason));
}
// 静态 all 方法
static all(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument must be an array'));
}
const results = [];
let count = 0;
const len = promises.length;
if (len === 0) {
return resolve(results);
}
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
value => {
results[index] = value;
count++;
if (count === len) {
resolve(results);
}
},
reason => {
reject(reason);
}
);
});
});
}
// 静态 race 方法
static race(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument must be an array'));
}
promises.forEach(promise => {
MyPromise.resolve(promise).then(resolve, reject);
});
});
}
// 静态 allSettled 方法
static allSettled(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument must be an array'));
}
const results = [];
let count = 0;
const len = promises.length;
if (len === 0) {
return resolve(results);
}
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
value => {
results[index] = { status: 'fulfilled', value };
count++;
if (count === len) {
resolve(results);
}
},
reason => {
results[index] = { status: 'rejected', reason };
count++;
if (count === len) {
resolve(results);
}
}
);
});
});
}
// 静态 any 方法
static any(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument must be an array'));
}
const errors = [];
let count = 0;
const len = promises.length;
if (len === 0) {
return reject(new AggregateError([], 'All promises were rejected'));
}
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
value => {
resolve(value);
},
reason => {
errors[index] = reason;
count++;
if (count === len) {
reject(new AggregateError(errors, 'All promises were rejected'));
}
}
);
});
});
}
}
使用示例
// 基本使用
const promise1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功');
}, 1000);
});
promise1.then(value => {
console.log(value); // 输出: 成功
return '链式调用';
}).then(value => {
console.log(value); // 输出: 链式调用
});
// catch 使用
const promise2 = new MyPromise((resolve, reject) => {
reject('失败');
});
promise2.catch(error => {
console.log(error); // 输出: 失败
});
// finally 使用
const promise3 = new MyPromise((resolve, reject) => {
resolve('完成');
});
promise3
.then(value => console.log(value))
.finally(() => console.log('清理工作'));
// Promise.all 使用
MyPromise.all([
MyPromise.resolve(1),
MyPromise.resolve(2),
MyPromise.resolve(3)
]).then(results => {
console.log(results); // 输出: [1, 2, 3]
});
// Promise.race 使用
MyPromise.race([
new MyPromise(resolve => setTimeout(() => resolve(1), 1000)),
new MyPromise(resolve => setTimeout(() => resolve(2), 500))
]).then(result => {
console.log(result); // 输出: 2
});
// Promise.allSettled 使用
MyPromise.allSettled([
MyPromise.resolve(1),
MyPromise.reject('error'),
MyPromise.resolve(3)
]).then(results => {
console.log(results);
// 输出: [
// { status: 'fulfilled', value: 1 },
// { status: 'rejected', reason: 'error' },
// { status: 'fulfilled', value: 3 }
// ]
});
// Promise.any 使用
MyPromise.any([
MyPromise.reject('error1'),
MyPromise.resolve(2),
MyPromise.reject('error2')
]).then(result => {
console.log(result); // 输出: 2
});
关键点
- 状态管理:Promise 有三种状态(pending、fulfilled、rejected),状态一旦改变就不可逆
- 回调队列:使用数组存储异步情况下的回调函数,状态改变时统一执行
- then 方法链式调用:每次调用 then 都返回一个新的 Promise 实例
- resolvePromise 方法:处理 then 回调的返回值,支持返回普通值、Promise 实例或 thenable 对象
- 循环引用检测:防止 then 返回自身导致的死循环
- 异步执行:使用 setTimeout 模拟微任务,确保回调异步执行
- 错误处理:executor 执行错误、回调执行错误都需要捕获并 reject
- 静态方法实现:all、race、allSettled、any 等方法需要正确处理多个 Promise 的并发场景
- 参数校验:对传入的参数进行类型检查,提供默认值或抛出错误
- thenable 对象处理:支持具有 then 方法的对象,实现 Promise 互操作性
目录