返回
手写Promise实战,面试官直呼牛x
前端
2023-09-17 09:36:14
手把手教你编写自己的 Promise
在前端开发中,Promise 是一个必不可少的工具,它允许我们处理异步操作并编写更简洁和可维护的代码。虽然 Promise 内部的机制可能看起来很复杂,但理解其工作原理至关重要。在这篇文章中,我们将深入探讨如何从头开始编写一个 Promise,并为你提供一个易于理解的逐步指南。
1. Promise 的核心:一个简单又强大的类
我们从创建一个 Promise 类开始。它是一个蓝图,用于生成 Promise 实例,其中包含处理异步操作所需的基本功能。
class Promise {
constructor(executor) {
this.state = "pending"; // Promise 的初始状态
this.value = undefined; // 存储最终结果(如果 Promise 成功)
this.reason = undefined; // 存储失败原因(如果 Promise 失败)
this.onFulfilledCallbacks = []; // 成功回调函数队列
this.onRejectedCallbacks = []; // 失败回调函数队列
// 立即执行 executor 函数,传递 resolve 和 reject 函数
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (err) {
this.reject(err); // 如果 executor 函数抛出异常,则直接拒绝 Promise
}
}
}
2. 解析和拒绝:改变 Promise 的状态
接下来,我们定义 resolve 和 reject 函数,它们用于改变 Promise 的状态并存储结果或失败原因。
resolve(value) {
if (this.state !== "pending") return; // 确保只有在 Promise 处于待定状态时才能解析它
this.state = "fulfilled"; // 将状态更改为已完成
this.value = value; // 存储最终结果
// 执行所有已注册的成功回调函数
for (const callback of this.onFulfilledCallbacks) {
callback(value);
}
}
reject(reason) {
if (this.state !== "pending") return; // 确保只有在 Promise 处于待定状态时才能拒绝它
this.state = "rejected"; // 将状态更改为已拒绝
this.reason = reason; // 存储失败原因
// 执行所有已注册的失败回调函数
for (const callback of this.onRejectedCallbacks) {
callback(reason);
}
}
3. then:连接 Promise,处理结果和错误
then 方法是 Promise 的核心。它允许我们链接多个 Promise 并处理结果和错误。
then(onFulfilled, onRejected) {
return new Promise((resolve, reject) => {
// 如果 onFulfilled 是函数,将其添加到成功回调队列
if (typeof onFulfilled === "function") {
this.onFulfilledCallbacks.push(() => {
try {
const result = onFulfilled(this.value);
resolve(result); // 将成功回调函数的结果解析为新的 Promise
} catch (err) {
reject(err); // 如果成功回调函数抛出异常,则拒绝新的 Promise
}
});
}
// 如果 onRejected 是函数,将其添加到失败回调队列
if (typeof onRejected === "function") {
this.onRejectedCallbacks.push(() => {
try {
const result = onRejected(this.reason);
resolve(result); // 将失败回调函数的结果解析为新的 Promise
} catch (err) {
reject(err); // 如果失败回调函数抛出异常,则拒绝新的 Promise
}
});
}
// 如果 Promise 已解决或拒绝,立即执行回调函数
if (this.state !== "pending") {
this.state === "fulfilled"
? this.onFulfilledCallbacks[0]()
: this.onRejectedCallbacks[0]();
}
});
}
4. catch:简化错误处理
catch 方法是一个语法糖,它允许我们只指定一个失败回调函数,以简化错误处理。
catch(onRejected) {
return this.then(undefined, onRejected);
}
5. finally:无论 Promise 结果如何都执行的代码
finally 方法允许我们在 Promise 无论成功还是失败时都执行一些代码。
finally(onFinally) {
return this.then(
() => onFinally(), // 成功时执行 onFinally
() => onFinally() // 失败时执行 onFinally
);
}
示例:将 Promise 投入实践
让我们通过一个示例来看一个 Promise 是如何工作的:
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("数据已加载!");
}, 2000);
});
myPromise
.then(result => {
console.log(result); // 输出:数据已加载!
})
.catch(error => {
console.error(error); // 如果发生错误,将在此处处理
});
结论
通过编写自己的 Promise,你可以深入了解其内部机制,并获得对其功能的更深入理解。通过掌握 Promise,你可以编写异步代码,提高可维护性和代码可读性,从而提升你的前端开发技能。
常见问题解答
- 为什么使用 Promise?
Promise 使得管理异步操作变得更容易,避免了回调函数的“地狱”。 - Promise 的状态有哪些?
有三个状态:“pending”、“fulfilled”和“rejected”。 - then 方法如何工作?
then 方法返回一个新的 Promise,该 Promise 在原始 Promise 解析或拒绝时被解析。 - catch 方法与 then 方法有何不同?
catch 方法是一个简写,它允许只指定一个失败回调函数。 - finally 方法有什么用?
finally 方法允许在 Promise 无论成功还是失败时都执行一些代码。