手写 Promise 从入门到掌握进阶版
2023-10-30 15:52:57
从零开始手写 Promise
在现代 JavaScript 开发中,处理异步操作至关重要。Promise 应运而生,为我们提供了一种优雅而强大的解决方案,让我们能够以可控且可预测的方式处理异步代码。本文将深入探讨 Promise 的内部原理,引导你逐步实现一个符合 Promise A+ 规范的手写 Promise。
什么是 Promise?
Promise 是一种对象,它代表着一个异步操作的最终结果,无论是成功还是失败。当异步操作完成后,Promise 会被标记为已完成或已拒绝,并提供一个结果值或一个错误原因。
手写一个简单的 Promise
让我们从一个基本 Promise 实现开始。这是一个简化的版本,重点在于理解核心概念:
class Promise {
constructor(executor) {
this.state = "pending";
this.value = null;
this.error = null;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
executor(this.resolve.bind(this), this.reject.bind(this));
}
resolve(value) {
if (this.state === "pending") {
this.state = "fulfilled";
this.value = value;
this.onFulfilledCallbacks.forEach(callback => callback(value));
}
}
reject(error) {
if (this.state === "pending") {
this.state = "rejected";
this.error = error;
this.onRejectedCallbacks.forEach(callback => callback(error));
}
}
then(onFulfilled, onRejected) {
if (this.state === "fulfilled") {
onFulfilled(this.value);
} else if (this.state === "rejected") {
onRejected(this.error);
} else {
this.onFulfilledCallbacks.push(onFulfilled);
this.onRejectedCallbacks.push(onRejected);
}
return new Promise((resolve, reject) => {
this.then(value => {
try {
const result = onFulfilled(value);
resolve(result);
} catch (error) {
reject(error);
}
}, error => {
try {
const result = onRejected(error);
resolve(result);
} catch (error) {
reject(error);
}
});
});
}
catch(onRejected) {
return this.then(null, onRejected);
}
}
这个 Promise 实现的基本原理如下:
- executor 函数:它接受两个参数:一个用于解析 Promise 的函数
resolve
和一个用于拒绝 Promise 的函数reject
。 - 状态 :Promise 有三种可能的状态:
pending
(等待)、fulfilled
(已完成)和rejected
(已拒绝)。 - 结果和错误 :当 Promise 完成时,它会存储一个结果值或一个错误原因。
- 回调队列 :
onFulfilledCallbacks
和onRejectedCallbacks
队列存储着在 Promise 完成或拒绝时要调用的回调函数。 - 链式调用 :
then()
方法允许你链式调用多个 Promise,这样可以优雅地处理异步操作序列。
符合 Promise A+ 规范的 Promise
Promise A+ 规范定义了一组规则,以确保不同 Promise 实现之间的一致性。为了符合规范,我们的 Promise 实现需要一些修改:
- 处理特殊情况,例如
executor
函数抛出错误或多次调用resolve
或reject
。 - 实现 Promise 链式调用,即
then()
方法返回的 Promise 能够继续使用then()
方法进行链式调用。 - 实现静态方法,例如
Promise.all()
,Promise.race()
,Promise.resolve()
和Promise.reject()
。
Promise 的进阶应用
一旦掌握了 Promise 的基础知识,就可以探索其更高级的特性:
- Promise.all() :将多个 Promise 包装成一个新的 Promise,并等待所有 Promise 完成。
- Promise.race() :将多个 Promise 包装成一个新的 Promise,并等待第一个 Promise 完成或拒绝。
- Promise.resolve() :将一个值包装成一个已完成的 Promise。
- Promise.reject() :将一个错误包装成一个已拒绝的 Promise。
总结
通过手写 Promise,我们不仅深入了解了它的内部原理,还为我们提供了在 JavaScript 开发中有效利用 Promise 的工具。Promise 的强大功能在于它提供了对异步操作的结构化和可控处理方式,使编写更健壮、更可维护的代码成为可能。
常见问题解答
-
为什么使用 Promise 而不用回调函数?
Promise 提供了更优雅和可维护的方式来处理异步操作。它消除了回调函数的嵌套,使代码更易于阅读和理解。 -
什么时候应该使用
then()
和catch()
?
then()
用于处理 Promise 完成时的结果,而catch()
用于处理 Promise 拒绝时的错误。 -
如何处理 Promise 链式调用中的错误?
每个then()
方法都返回一个新的 Promise,因此可以在链式调用的任何点使用catch()
来处理错误。 -
Promise.all() 和 Promise.race() 有什么区别?
Promise.all()
等待所有 Promise 完成,而Promise.race()
等待第一个 Promise 完成或拒绝。 -
如何使用 Promise 进行并行异步操作?
可以使用Promise.all()
将多个异步操作包装成一个 Promise,并等待所有操作完成。