使用 JavaScript 实现 Promise
JavaScript 的 Promise 是一种用于处理异步操作的机制,它代表一个可能在未来完成或失败的操作及其结果值。下面我们将手动实现一个简单的 Promise 类,来深入理解其工作原理。
1. Promise 类的基本结构
首先,我们需要定义一个 Promise 类,并在构造函数中接受一个执行器函数(executor),该函数接收两个参数:resolve 和 reject。
class MyPromise {
constructor(executor) {
this.state = 'pending'; // 初始状态
this.value = undefined; // 成功时的值
this.reason = undefined; // 失败时的原因
this.onResolvedCallbacks = []; // 存储成功时的回调
this.onRejectedCallbacks = []; // 存储失败时的回调
const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled'; // 状态变为成功
this.value = value;
this.onResolvedCallbacks.forEach(callback => callback(value)); // 执行所有成功的回调
}
};
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected'; // 状态变为失败
this.reason = reason;
this.onRejectedCallbacks.forEach(callback => callback(reason)); // 执行所有失败的回调
}
};
try {
executor(resolve, reject); // 执行传入的函数
} catch (err) {
reject(err); // 捕获异常并拒绝
}
}
// then 方法
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
if (this.state === 'fulfilled') {
// 如果已经成功,直接执行成功回调
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolve(x);
} catch (err) {
reject(err);
}
});
}
if (this.state === 'rejected') {
// 如果已经失败,直接执行失败回调
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolve(x);
} catch (err) {
reject(err);
}
});
}
// 如果仍然是 pending,存储回调
if (this.state === 'pending') {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolve(x);
} catch (err) {
reject(err);
}
});
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolve(x);
} catch (err) {
reject(err);
}
});
});
}
});
}
}
2. Promise 的基本用法
现在我们已经实现了一个基本的 Promise 类,下面是如何使用它的示例。
const myPromise = new MyPromise((resolve, reject) => {
setTimeout(() => {
const success = true; // 模拟成功或失败
if (success) {
resolve('操作成功');
} else {
reject('操作失败');
}
}, 1000);
});
myPromise
.then(result => {
console.log(result); // 输出: 操作成功
return '继续处理';
})
.then(result => {
console.log(result); // 输出: 继续处理
})
.catch(error => {
console.error(error); // 如果失败,输出错误信息
});
3. Promise.all 和 Promise.race
为了增强我们的 Promise 实现,我们可以添加 Promise.all 和 Promise.race 方法。
MyPromise.all = function(promises) {
return new MyPromise((resolve, reject) => {
let resolvedCounter = 0;
const results = [];
promises.forEach((promise, index) => {
promise.then(value => {
resolvedCounter++;
results[index] = value;
if (resolvedCounter === promises.length) {
resolve(results); // 所有 Promise 都成功时返回结果
}
}).catch(reject); // 任意一个 Promise 失败则直接 reject
});
});
};
MyPromise.race = function(promises) {
return new MyPromise((resolve, reject) => {
promises.forEach(promise => {
promise.then(resolve).catch(reject);
});
});
};
结论
通过手动实现 Promise,我们可以更深入地理解其内部机制。Promise 提供了一种优雅的方式来处理异步操作,避免了回调地狱的问题。尽管 JavaScript 已经原生支持 Promise,但学习如何实现它有助于我们更好地掌握异步编程的理念。