它是什么
Promise可以看做一个承诺------当前某事还未解决,但未来一定会解决,常用来处理异步操作。
举个例子:你点了一份菜,商家承诺半小时内上菜。这就是Promise。
它解决了什么问题
Promise的链式调用完美解决了回调地狱的问题。
js
function doSomething(){
console.log("doSomething");
function doSomething2(){
console.log("doSomething2");
function doSomething3(){
console.log("doSomething3");
}
}
}
例如这个经典的回调地狱,当函数的嵌套层级足够多时,代码的可阅读性、可维护性难度会成倍增长。如果改成Promise链式调用,就会非常清晰。
js
doSomething()
.then(() => {
console.log("doSomething");
return doSomething2();
})
.then(() => {
console.log("doSomething2");
return doSomething3();
})
.then(() => {
console.log("doSomething3");
})
在小程序开发中,将小程序API改为Promise形式进行链式调用非常有用,否则就容易产生回调地狱。
它是怎么工作的
状态流转
Promise有3种状态:
- pending:待定,事情还未处理完成。
- fulfilled:已兑现,事情成功处理完成。
- rejected:已拒绝,事情处理失败。
同样是点菜的例子:
- 点菜后到上菜前都是
pending状态。此时后厨在备菜,或者服务员在忙,还未上你这一桌的菜。 - 服务员把菜端到桌上,此时是
fulfilled状态。菜品已经成功做出并端上桌。 - 服务员过来告诉你因为生意太好,你点的菜已经卖完了。此时是
rejected状态。出了一点小意外,你点的菜没吃上。
此外,还有两种常说的状态------resolved(已解决)、settled(已敲定)------不是Promise的基本状态,是归类用的。一起看看在点菜的例子中是怎么体现的。
- 点菜后到上菜前都是
pending状态。 - 后厨做好菜,等待服务员来端走,此时是
resolved状态。 - 服务员把菜端到桌上,此时是
fulfilled状态。 - 服务员上菜过程中摔了一跤,菜打翻了,此时是
rejected状态。 - 无论是服务员成功把菜端到桌上还是打翻了菜,通知到你都是
settled状态。
settled状态非常好理解,在这个状态时,点菜的结果已经确定并且不会再发生改变 ------成功上菜或菜打翻了。resolved状态怎么理解呢?我们知道,在餐厅里,后厨工作人员和服务员通常不是同一个人,因此点餐后的处理是分为了两个环节------后厨备菜、服务员上菜。后厨做好菜通知到服务员(后厨的工作已完成),等待服务员上菜给顾客(整个点菜过程完成)。这种一个环节完成,依赖另一个环节完成才能最终完成 的状态就叫resolved。如果后厨和服务员是同一个人,做好菜立马上菜成功,这个时候resolved基本就等价于fulfilled。
js
const waiter = new Promise((resolve, reject) => {
setTimeout(() => resolve("服务员成功上菜"), 1000); // 执行这个,最终是fulfilled状态
// 或
// setTimeout(() => reject("服务员打翻了菜"), 1000); // 执行这个,最终是rejected状态
});
const chef = new Promise((resolve) => {
console.log("厨师备菜完成,等待上菜");
resolve(waiter); // 此时是resolved状态,依赖服务员上菜环节
});
// 在.then()或.catch()被执行前,是pending状态
// 无论执行.then()还是.catch(),都是settled状态
chef
.then((res) => console.log("点菜成功:", res))
.catch((err) => console.log("点菜失败:", err));
链式调用
在链式调用中,常用到三个函数:.then()、.catch()、.finally(),一起来看看这三个函数。
Promise.prototype.then
.then()接收两个参数:onFulfilled、onRejected,分别用于处理前一个Promise的fulfilled、rejected状态。
js
const p1 = new Promise((resolve, reject) => {
resolve("p1 resolve");
// 或
// reject("p1 reject");
});
p1.then(
(result) => {
console.log(result);
},
(error) => {
console.log(error);
},
);
比较特殊的是,如果参数onFulfilled不是一个函数,那将仅做向前传递数据的作用。如果参数onRejected不是一个函数,将抛出接收到的异常。
js
const p1 = new Promise((resolve, reject) => {
resolve("p1 resolve");
});
const p2 = p1.then("p2 resolve"); // 此处将被替换为恒等函数:(result) => result
p2.then((result) => {
console.log(result); // p1 resolve
});
const p3 = new Promise((resolve, reject) => {
reject("p3 reject");
});
const p4 = p3.then("p4 resolve", "p4 reject"); // 此处将被替换为恒等函数:(error) => { throw error; }
p4.then(
(result) => {
console.log(result);
},
(error) => {
console.log(error); // p3 reject
},
);
.then()是.catch()和.finally()的基础:
.catch()等价于.then(undefined,onRejected())。.finally()等价于.then(onFinally(),onFinally())。
Promise.prototype.catch
.catch()接收一个onRejected作为参数。当且仅当Promise的状态为rejected时,.catch()才会被执行。
在.catch()里可以返回新的Promise状态,以使下一段链式调用进入不同的处理分支。
js
const p1 = Promise.reject("p1 抛出异常");
p1.catch((err) => {
console.log(err);
return Promise.reject();
})
.then(() => console.log("next then"))
.catch(() => console.log("next catch"));
// p1 抛出异常
// next catch
在
.catch()中没有返回新的Promise状态时,默认为fulfilled状态,可以在.catch()后链式调用.then()。
最重要的一点是:在链式调用时,只需在链条最后调用一次.catch(),即可捕获任一节点的错误。
js
const p1 = new Promise((resolve) => {
resolve("p1 resolve");
});
const p2 = new Promise((resolve, reject) => {
reject("p2 reject");
});
const p3 = new Promise((resolve) => {
resolve("p3 resolve");
});
p1.then((result1) => {
console.log(result1); // p1 resolve
return p2;
})
.then((result2) => {
console.log(result2);
return p3;
})
.then((result3) => {
console.log(result3);
})
.catch((error) => {
console.log(error); // p2 reject
});
Promise.prototype.finally
.finally()接收一个onFinally作为参数。在.finally()中,Promise的状态已经确定,要么是fulfilled,要么是rejected。
同时,在onFinally()做的任何操作不会改变Promise的状态。
js
const doSomething = new Promise((resolve) => resolve("success"));
doSomething
.then((res) => console.log(res))
.finally(() => {
Promise.reject("finally抛出异常");
setTimeout(() => {
console.log('finally抛出异常后',doSomething);
}, 1000);
});

适用于无需依赖Promise最终状态做相应处理的场景。
js
const waiter = new Promise((resolve) => {
setTimeout(() => resolve("服务员成功上菜"), 1000);
});
const chef = new Promise((resolve) => {
console.log("厨师备菜完成,等待上菜");
resolve(waiter);
});
const isWaiting = ref(false);
chef
.then((res) => console.log("点菜成功:", res))
.catch((err) => console.log("点菜失败:", err))
.finally(() => {
isWaiting.value = false;
});
Promise并发
Promise.all
Promise.all接收一个Promise数组作为参数。当且仅当所有Promise都是fulfilled状态时,可以得到包含所有Promise返回值的数组。否则返回第一个rejected的Promise的错误信息。
js
const p1 = new Promise((resolve, reject) => {
resolve("p1 resolve");
});
const p2 = new Promise((resolve, reject) => {
resolve("p2 resolve");
});
const p3 = new Promise((resolve, reject) => {
resolve("p3 resolve");
// 或
// reject("p3 reject");
});
Promise.all([p1, p2, p3])
.then((results) => {
console.log(results); // 如果p3执行了resolve(),打印:['p1 resolve', 'p2 resolve', 'p3 resolve']
})
.catch((error) => {
console.log(error); // 如果p3执行了reject(),打印: p3 reject
});
Promise.allSettled
Promise.allSettled接收一个Promise数组作为参数。返回一个包含所有Promise执行结果 的数组(不会执行.catch)。
js
const p1 = new Promise((resolve, reject) => {
resolve("p1 resolve");
});
const p2 = new Promise((resolve, reject) => {
resolve("p2 resolve");
});
const p3 = new Promise((resolve, reject) => {
reject("p3 reject");
});
Promise.allSettled([p1, p2, p3]).then((results) => {
console.log(results);
});
// [
// { "status": "fulfilled","value": "p1 resolve" },
// { "status": "fulfilled","value": "p2 resolve" },
// { "status": "rejected","reason": "p3 reject" }
// ]
Promise.any
Promise.any接收一个Promise数组作为参数。只要有一个Promise是fulfilled状态,就返回该Promise的返回值。
所有Promise都是
rejected状态时,抛出异常:AggregateError: All promises were rejected。
js
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p1 resolve");
}, 300);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p2 resolve");
}, 100);
});
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("p3 reject");
}, 200);
});
Promise.race([p1, p2, p3]).then((result) => {
console.log(result); // p2执行更快,打印: p2 resolve
});
Promise.race
Promise.race接收一个Promise数组作为参数。只要有一个Promise执行完成(无论是fulfilled还是rejected),就执行对应的.then()或.catch()。
js
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p1 resolve");
}, 300);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p2 resolve");
}, 100);
});
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("p3 reject");
}, 50);
});
Promise.race([p1, p2, p3])
.then((result) => {
console.log(result); // 不会执行
})
.catch((error) => {
console.log(error); // p3更快执行完成,打印:p3 reject
});