返回
手把手教你手写一个 Promise,一文带你玩转异步编程!
前端
2023-09-23 06:46:11
一、为什么会有 Promise 的出现?
在 JavaScript 中,我们经常会遇到异步操作,如网络请求、文件读取等。这些操作需要一段时间才能完成,在等待结果期间,我们需要一种机制来处理后续操作。传统的回调函数虽然可以实现这个目的,但当异步操作嵌套过多时,代码就会变得混乱不堪,难以维护和理解。
为了解决这个问题,Promise 应运而生。它是一种用于处理异步操作的规范,它提供了统一的接口来处理异步操作的成功和失败,使得代码更加清晰和易读。
二、Promise 基础
Promise 对象用于表示一个异步操作的最终完成(或失败)及其结果值。它有三种状态:
- 待定(pending) :初始状态,既没有被兑现(resolved)也没有被拒绝(rejected)。
- 兑现(resolved) :异步操作成功完成,Promise 对象的值被设置。
- 拒绝(rejected) :异步操作失败,Promise 对象的错误信息被设置。
Promise 对象提供了几个基础方法来处理不同的状态:
- then() :用于注册回调函数,分别处理兑现和拒绝两种情况。
- catch() :用于注册回调函数,仅处理拒绝的情况。
- finally() :无论兑现还是拒绝,都会执行的回调函数。
三、手写一个 Promise
现在,我们来看看如何手写一个 Promise:
class Promise {
constructor(executor) {
this.state = "pending"; // 初始状态
this.value = null; // 值
this.reason = null; // 错误信息
this.onFulfilledCallbacks = []; // 兑现回调函数队列
this.onRejectedCallbacks = []; // 拒绝回调函数队列
// 执行器函数,负责执行异步操作并设置状态和值
try {
executor(
(value) => {
this.resolve(value); // 兑现
},
(reason) => {
this.reject(reason); // 拒绝
}
);
} catch (err) {
this.reject(err); // 如果执行器函数抛出错误,则拒绝
}
}
resolve(value) {
if (this.state !== "pending") return; // 状态不是待定,直接返回
this.state = "fulfilled"; // 更改状态为兑现
this.value = value; // 设置值
this.onFulfilledCallbacks.forEach((callback) => {
// 执行兑现回调函数
callback(value);
});
}
reject(reason) {
if (this.state !== "pending") return; // 状态不是待定,直接返回
this.state = "rejected"; // 更改状态为拒绝
this.reason = reason; // 设置错误信息
this.onRejectedCallbacks.forEach((callback) => {
// 执行拒绝回调函数
callback(reason);
});
}
then(onFulfilled, onRejected) {
return new Promise((resolve, reject) => {
// 将兑现回调函数添加到队列中
this.onFulfilledCallbacks.push((value) => {
try {
const result = onFulfilled(value);
// 如果 onFulfilled 返回一个 Promise,则等待其结果
if (result instanceof Promise) {
result.then(resolve, reject);
} else {
// 否则,直接兑现
resolve(result);
}
} catch (err) {
// 如果 onFulfilled 抛出错误,则拒绝
reject(err);
}
});
// 将拒绝回调函数添加到队列中
this.onRejectedCallbacks.push((reason) => {
try {
const result = onRejected(reason);
// 如果 onRejected 返回一个 Promise,则等待其结果
if (result instanceof Promise) {
result.then(resolve, reject);
} else {
// 否则,直接兑现
resolve(result);
}
} catch (err) {
// 如果 onRejected 抛出错误,则拒绝
reject(err);
}
});
});
}
catch(onRejected) {
return this.then(null, onRejected);
}
finally(onFinally) {
return this.then(
(value) => {
onFinally();
return value;
},
(reason) => {
onFinally();
return reason;
}
);
}
}
四、Promise 实例
现在,我们可以使用我们的 Promise 来处理异步操作了:
const promise = new Promise((resolve, reject) => {
// 模拟异步操作
setTimeout(() => {
// 成功
resolve("成功!");
}, 2000);
});
promise.then((value) => {
// 兑现回调函数
console.log(value); // "成功!"
}).catch((reason) => {
// 拒绝回调函数
console.log(reason); // 不会被执行
});
五、Promise 链式调用
Promise 还支持链式调用,我们可以通过 .then()
方法将多个异步操作串联起来,形成一个异步操作队列:
promise.then((value) => {
console.log(value); // "成功!"
return "新的值"; // 返回一个新的值
}).then((value) => {
console.log(value); // "新的值"
}).catch((reason) => {
// 不会被执行
});
六、总结
Promise 是 JavaScript 中处理异步操作的利器,它提供了统一的接口来处理异步操作的成功和失败,使得代码更加清晰和易读。通过手写 Promise,我们不仅可以加深对 Promise 的理解,还可以为异步编程打下坚实的基础。
希望这篇博客对您有所帮助,如果您有任何问题或建议,欢迎在评论区留言!