返回
手写Promise,夯实基础,掌握异步编程利器
前端
2024-02-13 08:39:44
## 前言
在现代前端开发中,异步编程已成为不可或缺的一部分。随着应用程序变得越来越复杂,我们需要处理越来越多的异步任务,例如网络请求、定时器、事件处理等等。为了更好地管理和协调这些异步任务,JavaScript 引入了 Promise 对象。
Promise 是一个表示异步操作及其最终结果的 JavaScript 对象。它提供了一种统一、简单的方式来处理异步操作,使得代码更易读、更易维护。
## 手写 Promise
为了深入理解 Promise 的工作原理,我们不妨尝试自己手写一个 Promise。
```javascript
class Promise {
constructor(executor) {
this.state = 'pending'; // 初始状态为 pending
this.value = undefined; // 最终值
this.reason = undefined; // 拒绝原因
this.onFulfilledCallbacks = []; // 保存成功的回调函数
this.onRejectedCallbacks = []; // 保存失败的回调函数
// 执行器函数立即执行,传入 resolve 和 reject 函数
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled, onRejected) {
// 规范要求,如果 onFulfilled 或 onRejected 不是函数,则直接忽略
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => value;
onRejected = typeof onRejected === 'function' ? onRejected : (reason) => { throw reason; };
// 返回一个新的 Promise 对象
return new Promise((resolve, reject) => {
// 将成功回调和失败回调添加到相应的数组中
this.onFulfilledCallbacks.push(() => {
// 将成功回调执行结果传递给下一个 Promise 的 resolve 函数
resolve(onFulfilled(this.value));
});
this.onRejectedCallbacks.push(() => {
// 将失败回调执行结果传递给下一个 Promise 的 reject 函数
reject(onRejected(this.reason));
});
// 如果 Promise 状态已经确定,则立即执行回调
if (this.state === 'fulfilled') {
this.onFulfilledCallbacks[0]();
} else if (this.state === 'rejected') {
this.onRejectedCallbacks[0]();
}
});
}
catch(onRejected) {
return this.then(null, onRejected);
}
finally(onFinally) {
return this.then(
(value) => {
onFinally();
return value;
},
(reason) => {
onFinally();
throw reason;
}
);
}
resolve(value) {
if (this.state !== 'pending') {
return;
}
this.state = 'fulfilled';
this.value = value;
// 执行成功回调
this.onFulfilledCallbacks.forEach((callback) => {
callback();
});
}
reject(reason) {
if (this.state !== 'pending') {
return;
}
this.state = 'rejected';
this.reason = reason;
// 执行失败回调
this.onRejectedCallbacks.forEach((callback) => {
callback();
});
}
}
Promise 的工作原理
从手写 Promise 的代码中,我们可以看到 Promise 的工作原理大致如下:
- Promise 构造函数接受一个 executor 函数作为参数,executor 函数立即执行,传入 resolve 和 reject 函数。
- executor 函数中,通过调用 resolve 函数来将 Promise 的状态从 pending 更改为 fulfilled,并将结果值作为参数传递给 resolve 函数。
- executor 函数中,通过调用 reject 函数来将 Promise 的状态从 pending 更改为 rejected,并将错误原因作为参数传递给 reject 函数。
- then 方法用于在 Promise 状态改变时添加回调函数。当 Promise 状态为 fulfilled 时,会执行成功的回调函数;当 Promise 状态为 rejected 时,会执行失败的回调函数。
- catch 方法用于处理 Promise 的失败情况。它相当于 then 方法的简写形式,只有失败的回调函数。
- finally 方法用于在 Promise 状态改变后执行的回调函数,无论 Promise 是成功还是失败。
Promise 的使用
在实际开发中,我们可以直接使用 JavaScript 内置的 Promise 对象,而无需自己手写 Promise。Promise 的使用非常简单,只需要按照以下步骤即可:
- 创建一个 Promise 对象。
- 在 Promise 对象中,使用 then 方法添加成功和失败的回调函数。
- 在 Promise 对象中,使用 resolve 函数来将 Promise 的状态从 pending 更改为 fulfilled,并将结果值作为参数传递给 resolve 函数。
- 在 Promise 对象中,使用 reject 函数来将 Promise 的状态从 pending 更改为 rejected,并将错误原因作为参数传递给 reject 函数。
const promise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
resolve('成功结果');
}, 1000);
});
promise.then(
(result) => {
console.log(result); // 输出:成功结果
},
(error) => {
console.log(error); // 不会执行
}
);
Promise 的注意事项
在使用 Promise 时,需要注意以下几点:
- Promise 对象一旦状态改变,就无法再改变。
- then 方法和 catch 方法都返回一个新的 Promise 对象。
- then 方法可以多次调用,每次调用都会添加一个新的回调函数。
- catch 方法只能调用一次,如果多次调用,只有第一次调用的回调函数会被执行。
- finally 方法总是会被执行,无论 Promise 是成功还是失败。
结语
Promise 是 JavaScript 中处理异步编程的利器,它使得代码更易读、更易维护。通过手写 Promise,我们可以深入理解 Promise 的工作原理和使用方法。在实际开发中,我们可以直接使用 JavaScript 内置的 Promise 对象,并遵循 Promise 的注意事项,以确保代码的正确性和健壮性。