深入剖析Promise 原理:逐步实现一个 Promise
2023-11-24 09:35:00
Promise 原理与实现
Promise 是 JavaScript 中用来处理异步操作的神奇工具,它可以帮助我们更优雅地处理异步代码。它到底是如何工作的呢?我们一起来一步步实现一个简单的 Promise。
首先,我们需要定义一个 Promise 构造函数。它接收一个函数作为参数,这个函数有两个参数:resolve 和 reject。resolve 用于表示异步操作成功,reject 用于表示异步操作失败。
function Promise(executor) {
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.state !== 'pending') return;
this.state = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach((callback) => {
callback(value);
});
};
const reject = (reason) => {
if (this.state !== 'pending') return;
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach((callback) => {
callback(reason);
});
};
executor(resolve, reject);
}
现在我们有了一个 Promise 构造函数,它可以用来创建一个 Promise 对象。我们可以通过调用 Promise 构造函数并传入一个执行器函数来创建一个 Promise 对象。执行器函数会在 Promise 对象创建时立即执行,它可以用来执行异步操作,并通过调用 resolve 或 reject 来改变 Promise 对象的状态。
状态变化与回调函数
Promise 对象的状态只能是三种:pending、fulfilled 和 rejected。状态一旦改变,就不可逆转。如果 Promise 对象的状态从 pending 变为 fulfilled,则会调用所有之前注册的 onFulfilled 回调函数;如果 Promise 对象的状态从 pending 变为 rejected,则会调用所有之前注册的 onRejected 回调函数。
我们可以通过调用 then 方法来注册回调函数。then 方法接收两个参数:onFulfilled 和 onRejected,它们分别表示 Promise 对象状态为 fulfilled 和 rejected 时要执行的回调函数。
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功了!');
}, 1000);
});
promise.then(
(value) => {
console.log(value); // 输出:'成功了!'
},
(reason) => {
console.log(reason); // 不会被调用
}
);
在上面的示例中,我们创建了一个 Promise 对象,并注册了两个回调函数。当 Promise 对象的状态变为 fulfilled 时,第一个回调函数会被调用;当 Promise 对象的状态变为 rejected 时,第二个回调函数会被调用。
链式调用与回调地狱
Promise 对象支持链式调用,这使得我们可以将多个 Promise 对象连接起来,形成一个链式结构。链式调用可以帮助我们避免回调地狱,让代码更清晰、更易维护。
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功了!');
}, 1000);
});
const promise2 = promise1.then((value) => {
console.log(value); // 输出:'成功了!'
return '另一个成功了!';
});
promise2.then((value) => {
console.log(value); // 输出:'另一个成功了!'
});
在上面的示例中,我们创建了一个 Promise 对象 promise1,并注册了一个回调函数。然后,我们通过调用 promise1.then 方法创建了一个新的 Promise 对象 promise2。promise2 的回调函数中,我们打印了 promise1 的值,并返回了一个新的值。最后,我们通过调用 promise2.then 方法注册了另一个回调函数,该回调函数打印了 promise2 的值。
链式调用使得我们可以将多个异步操作连接起来,形成一个清晰、易维护的代码结构。它避免了回调地狱,让代码更易于阅读和理解。