在学习JS的异步编程时,你总是绕不Promise。在开发时总是会接触它,用时觉得也没有什么,用的时候感觉也就那样,但是到了面试时的时候,一道道要你说出执行顺序的时候又犯了难。不知道你是不是跟我一样有这样的感受。本系列将以手写Promise的方式来了解Promise,在手写Promise的同时体验到各种开发技巧。提高一下自身的开发思维。
那我们开始手写Promise的旅程吧!
什么是Promise
Promise是什么呢?可以想象现实生活中的一个小场景:淘宝购物
。
- 当你看到了心仪的商品时,你点击购买然后付钱后,此处于发货和配送中。
- 当心仪商品配送到家后,最终会产生两种结果:
- 成功:实物和淘宝看到的一样非常满意。交易成功!
- 失败:实物和淘宝看到的相差甚远不是很满意。退货!
我们再来看看Promise是怎样的呢?
- Promise是一个对象,代表了一个异步操作最终完成的以及返回的结果。
- Promise操作时有三种状态:
- pending:初始状态,表示正在处理中。
- fulfilled:操作成功完成
- rejected:操作失败
- Promise的状态一旦发生改变,不能更改。这是Promise的关键特性。

为什么需要Promise
在没有Promise的时候,是怎样编写异步代码的呢?主要是回调函数。可以想象下网络请求调用后台接口时,一个接口依赖一个接口再依赖另一个接口的场景。通过回调函数如何编写呢?
js
/* jquery回调函数的书写方式 */
$.ajax({
url: "/api/userInfo",
type: "GET",
dataType: "json",
success: function (info) {
$.ajax({
url: "/api/roleInfo",
data: { userId: info.id },
success: function (role) {
$.ajax({
url: "api/menuInfo",
data: { roleId: role.id },
success: function () {
/* 还有可能需要调用其他接口*/
},
});
},
});
},
});
上述代码发现回调函数层层嵌套。形成了'金字塔'的形状。代码之间耦合度非常高,维护代码极其困难,一旦有错误处理起来比较困难。就像开发人员天天骂是一坨屎的代码
。😂
Promise的出现便是为了解决这样的问题而诞生的。它通过.then
和.catch
方法实现了链式调用。将异步的流程阅读性强,接近于同步线性流程。将上述代码改为promise的方式。
js
/* jquery支持Promise的书写方式 */
$.ajax({
url: "/api/userInfo",
type: "GET",
dataType: "json",
})
.then((info) => $.ajax({ url: "/api/roleInfo", data: { userId: info.id } }))
.then((role) => $.ajax({ url: "/api/menuInfo", data: { roleId: role.id } }))
.then(function (menu) { /* 还可以继续处理 */ })
.fail((error) => { /* 处理错误 */ });
修改后的代码从上往下的线性结构,在阅读代码和可维护性上都大大提升。错误处理上更加方便。
基本用法
知道promise为什么出现后,也知道了它的好处,那我们要如何使用它呢?首先要知道Promise是一个构造函数(new Promise(executor)
)。接收一个参数executor
函数。此函数会立刻执行
,它接收两个参数(也是函数):
resolve:
当异步操作成功时调用,将状态pending
改为fulfilled
reject:
当异步操作失败时调用,将状态pending
改为rejected
js
const p = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if(success) {
resolve('操作成功');
// reject('失败了'); // 此处不会执行 状态改为了fulfilled 不能再改为
} else {
reject('拒绝此操作');
// resolve('成功啦'); // 此处不会执行 状态改为了rejected 不能再改为
}
}, 1000)
})
Promise通过.then()
,.catch()
,.finally()
来接收成功和失败结果。
- .then(onFulfilled, onRejected):接收两个回调函数,分别处理成功和失败。然后返回一个新的Promise,这便是可以链式调用的原因。
- .catch(onRejected) :专门处理失败的,其实就是
.then(null, onRejected)
的语法糖。 - .finally(onFinally):无论成功或失败都会执行,一般用于清理工作。
js
const p = new Promise((resolve, reject) => {
resolve("lucy");
})
.then((name) => {
console.log(`接收到了面试人:${name}`); // 此处会执行
})
.catch((error) => {
console.log(error);
})
.finally(() => {
console.log("finally"); // 不管成功失败,都会执行
});
小结
本文讲述内容如下:
- 什么是Promise,它是一个构造函数,接收一个函数,初始化立即执行,此函数分别接收处理成功和失败的函数。
- Promise本质是一个状态机,包括三种状态:
pending
、fulfilled
、rejected
。状态一旦改变则不可逆 - then方法主要注册回调函数到对应状态上,并返回一个新的Promise以支持链式调用
- catch方法专门处理失败,finally方法是不管成功失败都会执行。
- Promise底层里的then/catch不是立即执行的,它是放入了微任务队列中,等待渲染主线程检测到后执行的。
了解Promise之后,接下来进行手写Promise工作了。