实现Promise相关方法
手写实现Promise方法,包括Promise构造函数、then、catch、finally以及静态方法resolve、reject、all、race、allSettled等
问题
Promise是JavaScript中处理异步操作的重要机制。本题要求手写实现Promise的功能,包括:
- Promise构造函数及基本状态管理
- 实例方法:then、catch、finally
- 静态方法:resolve、reject、all、race、allSettled、any
通过实现这些方法,理解Promise的工作原理和异步编程模式。
解答
// 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) => {
if (this.state === PENDING) {
this.state = FULFILLED;
this.value = value;
// 执行所有成功回调
this.onFulfilledCallbacks.forEach(fn => fn());
}
};
// 失败时调用
const reject = (reason) => {
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) {
// 使用微任务
queueMicrotask(() => {
try {
const x = onFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
} else if (this.state === REJECTED) {
queueMicrotask(() => {
try {
const x = onRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
} else if (this.state === PENDING) {
// 异步情况,将回调存入队列
this.onFulfilledCallbacks.push(() => {
queueMicrotask(() => {
try {
const x = onFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
});
this.onRejectedCallbacks.push(() => {
queueMicrotask(() => {
try {
const x = onRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
});
}
});
return promise2;
}
// 处理Promise解析过程
resolvePromise(promise2, x, resolve, reject) {
// 防止循环引用
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected'));
}
if (x instanceof MyPromise) {
// 如果x是Promise,则等待其状态改变
x.then(resolve, reject);
} 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));
}
// Promise.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 completedCount = 0;
const total = promises.length;
if (total === 0) {
return resolve(results);
}
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
value => {
results[index] = value;
completedCount++;
if (completedCount === total) {
resolve(results);
}
},
reason => {
reject(reason); // 任何一个失败就立即reject
}
);
});
});
}
// Promise.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);
});
});
}
// Promise.allSettled - 等待所有Promise完成
static allSettled(promises) {
return new MyPromise((resolve) => {
if (!Array.isArray(promises)) {
return resolve([]);
}
const results = [];
let completedCount = 0;
const total = promises.length;
if (total === 0) {
return resolve(results);
}
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
value => {
results[index] = { status: 'fulfilled', value };
completedCount++;
if (completedCount === total) {
resolve(results);
}
},
reason => {
results[index] = { status: 'rejected', reason };
completedCount++;
if (completedCount === total) {
resolve(results);
}
}
);
});
});
}
// Promise.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 rejectedCount = 0;
const total = promises.length;
if (total === 0) {
return reject(new AggregateError([], 'All promises were rejected'));
}
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
value => {
resolve(value); // 任何一个成功就立即resolve
},
reason => {
errors[index] = reason;
rejectedCount++;
if (rejectedCount === total) {
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) => {
resolve('完成');
});
promise3
.finally(() => {
console.log('清理工作'); // 无论成功失败都执行
})
.then(value => {
console.log(value); // 输出: 完成
});
// 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('慢'), 1000)),
new MyPromise(resolve => setTimeout(() => resolve('快'), 500))
]).then(result => {
console.log(result); // 输出: 快
});
// Promise.allSettled使用
MyPromise.allSettled([
MyPromise.resolve(1),
MyPromise.reject('错误'),
MyPromise.resolve(3)
]).then(results => {
console.log(results);
// 输出: [
// { status: 'fulfilled', value: 1 },
// { status: 'rejected', reason: '错误' },
// { status: 'fulfilled', value: 3 }
// ]
});
// Promise.any使用
MyPromise.any([
MyPromise.reject('错误1'),
MyPromise.resolve('成功'),
MyPromise.reject('错误2')
]).then(result => {
console.log(result); // 输出: 成功
});
关键点
- 状态管理:Promise有三种状态(pending、fulfilled、rejected),状态一旦改变就不可逆
- 回调队列:使用数组存储异步情况下的回调函数,状态改变时统一执行
- 微任务:使用
queueMicrotask确保回调在微任务队列中执行,符合Promise规范 - 链式调用:then方法返回新的Promise实例,支持链式调用
- 值穿透:then方法的参数不是函数时,提供默认函数实现值穿透
- 循环引用检测:在resolvePromise中检测并防止Promise循环引用
- Promise.all:所有Promise成功才成功,任一失败立即失败,保持结果顺序
- Promise.race:返回第一个完成的Promise结果,无论成功或失败
- Promise.allSettled:等待所有Promise完成,返回所有结果的状态和值
- Promise.any:任一Promise成功即成功,全部失败才失败
- 错误处理:使用try-catch捕获同步错误,通过reject传递异步错误
目录