用原生 JavaScript 构建 MyPromise,深入理解 Promise②
2023-09-28 17:17:49
了解 Promise 的工作原理对于任何认真的 JavaScript 开发人员来说都至关重要。掌握 Promise 的奥秘可以显着提高你的异步编程技能,并让你的代码更加优雅和可维护。
揭开 Promise 的面纱
在深入了解 MyPromise 之前,让我们回顾一下 Promise 的基本概念。Promise 是一个对象,表示一个异步操作的最终结果。它可以处于三种状态之一:
- Pending: 初始状态,表示操作尚未完成。
- Fulfilled: 操作成功完成,结果可以通过
.then()
方法获取。 - Rejected: 操作失败,拒绝的原因可以通过
.catch()
方法获取。
Promise 的强大之处在于它允许我们处理异步操作而不阻塞主线程。我们可以链式调用 .then()
和 .catch()
方法来处理 Promise 的结果,并执行后续操作。
构建 MyPromise
现在,我们准备动手构建我们的 MyPromise。首先,我们定义一个 executor 函数,它接受 resolve 和 reject 两个回调函数作为参数:
class MyPromise {
constructor(executor) {
this.state = "pending";
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
}
executor 函数在创建 MyPromise 实例时立即执行。它可以将 Promise 标记为 fulfilled 或 rejected 状态,并提供相应的值或拒绝原因。
接下来,我们定义 resolve 和 reject 方法:
resolve(value) {
if (this.state !== "pending") return;
this.state = "fulfilled";
this.value = value;
this.onFulfilledCallbacks.forEach(callback => callback(this.value));
}
reject(reason) {
if (this.state !== "pending") return;
this.state = "rejected";
this.reason = reason;
this.onRejectedCallbacks.forEach(callback => callback(this.reason));
}
resolve 方法将 Promise 标记为 fulfilled 状态并提供一个值,而 reject 方法将 Promise 标记为 rejected 状态并提供一个拒绝原因。
处理 Promise 的结果
我们还需要定义 .then()
和 .catch()
方法来处理 Promise 的结果:
then(onFulfilled, onRejected) {
if (typeof onFulfilled !== "function") onFulfilled = value => value;
if (typeof onRejected !== "function") onRejected = reason => { throw reason; };
const promise2 = new MyPromise((resolve, reject) => {
if (this.state === "fulfilled") {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
} else if (this.state === "rejected") {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
} else {
this.onFulfilledCallbacks.push(onFulfilled);
this.onRejectedCallbacks.push(onRejected);
}
});
return promise2;
}
catch(onRejected) {
return this.then(null, onRejected);
}
.then()
方法接受两个回调函数:onFulfilled 和 onRejected。如果 Promise 处于 fulfilled 状态,则调用 onFulfilled 回调函数,并将结果值传递给链式 Promise。如果 Promise 处于 rejected 状态,则调用 onRejected 回调函数,并将拒绝原因传递给链式 Promise。
符合 Promises/A+ 规范
为了确保 MyPromise 符合 Promises/A+ 规范,我们必须实现一些额外的规则,例如:
- Promise 的状态只能从 pending 转换到 fulfilled 或 rejected。
- Promise 必须异步地执行其 onFulfilled 和 onRejected 回调函数。
- 如果 onFulfilled 或 onRejected 回调函数抛出错误,则链式 Promise 应拒绝该错误。
- 如果 resolve 和 reject 多次调用,则 Promise 的状态只应在第一次调用时更改。
- 如果 resolve 和 reject 都调用,则 Promise 的状态应为 rejected,拒绝原因应为 reject 的最后一个参数。
真实世界的示例
让我们通过一个实际示例来展示 MyPromise 的强大功能:
const myPromise = new MyPromise((resolve, reject) => {
setTimeout(() => {
const randomNumber = Math.random();
if (randomNumber > 0.5) {
resolve("成功!");
} else {
reject("失败!");
}
}, 2000);
});
myPromise
.then(result => {
console.log(result); // "成功!"
})
.catch(error => {
console.error(error); // "失败!"
});
在这个示例中,我们创建了一个 MyPromise,它将在 2 秒后随机解析为 "成功!" 或 "失败!"。.then()
和 .catch()
方法用于处理 Promise 的结果并分别记录成功或失败消息。
结论
通过构建自己的 MyPromise,我们深入了解了 Promise 的内部机制。我们探索了 Promise 的状态、处理结果的方法,并确保我们实现的 MyPromise 符合 Promises/A+ 规范。通过实践这些概念,你可以大大提高你的 JavaScript 技能,并编写出更优雅和可维护的代码。