手撕 Promise:深入理解 JavaScript 异步编程
引言
JavaScript 的异步编程是前端开发中不可或缺的一部分。Promise 是处理异步操作的核心机制之一。理解 Promise 的内部实现可以帮助我们更好地掌握异步编程的精髓。本文将带你一步步实现一个简单的 Promise。
Promise 的基础
在开始手撕 Promise 之前,我们需要了解 Promise 的基本行为:
- Promise 有三种状态:Pending(等待中)、Fulfilled(已成功)、Rejected(已失败)。
- 一旦状态改变,它就成为不可变的。
- Promise 可以链式调用。
手动实现 Promise
定义 Promise 类
首先,我们定义一个 Promise 类,并初始化状态为 Pending。
class MyPromise {
constructor(executor) {
// 初始化状态为 Pending
this.state = 'pending';
this.value = undefined;
this.handlers = [];
try {
executor(this._resolve, this._reject);
} catch (err) {
this._reject(err);
}
}
_resolve = (value) => {
// 状态转换为 Fulfilled
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.handlers.forEach((h) => this._handle(h));
}
}
_reject = (error) => {
// 状态转换为 Rejected
if (this.state === 'pending') {
this.state = 'rejected';
this.value = error;
this.handlers.forEach((h) => this._handle(h));
}
}
_handle(handler) {
if (this.state === 'fulfilled' && typeof handler.onFulfilled === 'function') {
handler.onFulfilled(this.value);
}
if (this.state === 'rejected' && typeof handler.onRejected === 'function') {
handler.onRejected(this.value);
}
}
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
this.handlers.push({
onFulfilled: value => {
if (onFulfilled) {
try {
resolve(onFulfilled(value));
} catch (err) {
reject(err);
}
} else {
resolve(value);
}
},
onRejected: error => {
if (onRejected) {
try {
resolve(onRejected(error));
} catch (err) {
reject(err);
}
} else {
reject(error);
}
}
});
});
}
catch(onRejected) {
return this.then(null, onRejected);
}
}
使用自定义 Promise
现在我们可以使用这个自定义的 Promise 来处理异步操作。
const asyncTask = (time) => new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(`Task completed after ${time}ms`);
}, time);
});
asyncTask(1000).then(result => {
console.log(result); // Task completed after 1000ms
}).catch(error => {
console.error(error);
});
错误处理
我们的 Promise 实现也支持错误处理,如果 executor
函数抛出异常,或者 onFulfilled
或 onRejected
回调函数抛出异常,它们会被正确捕获并处理。
结论
通过手动实现 Promise,我们可以更深入地理解其内部机制和行为。这不仅是一种很好的学习方式,也是提高编程技能的有效途径。虽然在实际开发中我们很少需要手动实现 Promise,但这样的练习无疑加深了我们对异步编程的理解。