new Promise用法
promise要解决的问题
回调函数问题
问题一:回调函数多层嵌套调用(回调地狱)
问题二:每次回调的结果存在成功或失败的可能性
使用 promise 解决
解决问题一:promise 通过 .then 实现链式调用
解决问题二:promise 通过 .catch 统一捕获异常
Promise 的 3 种状态。
• fulfilled:表示操作已经成功完成,并准备返回结果。
• rejected:表示操作执行失败,代码可能有异常或人为地调用了 reject()。
• pending:如果状态既不是 fulfilled 也不是 rejected,则为 pending 状态,表示操作执行中。
使用 new 创建 Promise 对象之后,执行器中的代码会立即执行,此时 Promise 为 pending 状态;当调用 resolve() 函数之后,会把 Promise 的 pending 状态改为 fulfilled 状态;类似地,reject() 函数会把它从 pending 改为 rejected 状态。
fulfilled 和 rejected 状态统称为settled,可以认为是完成状态(无论是成功还是失败)。
基本语法如下:
const promise = new Promise((resolve, reject) => {
// asynchronous code goes here
});
我们首先使用Promise构造函数实例化一个新的 promise 对象,并向它传递一个回调函数。回调有两个参数,resolve和reject,它们都是函数。我们所有的异步代码都在该回调中。
如果一切运行成功,承诺将通过调用来实现resolve。如果出现错误,则会调用reject。我们可以将值传递给这两种方法,这些方法将在使用代码中可用。
Promise 提供了4种方式执行多个 Promise,分别是:
Promise.all()
Promise.allSettled()
Promise.any()
Promise.race()
接下来分别看一下它们的作用和区别。
1、Promise.all()
Promise.all() 静态方法接受一个 Promise 可迭代对象作为输入,并返回一个 Promise。当所有输入的 Promise 都被兑现时,返回的 Promise 也将被兑现(即使传入的是一个空的可迭代对象),并返回一个包含所有兑现值的数组。如果输入的任何 Promise 被拒绝,则返回的 Promise 将被拒绝,并带有第一个被拒绝的原因。
Promise.all 等待所有兑现(或第一个拒绝)的结果。
const p1 = Promise.resolve(3);
const p2 = 1337;
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("foo");
}, 100);
});
Promise.all([p1, p2, p3]).then((values) => {
console.log(values); // [3, 1337, "foo"]
});
2、Promise.allSettled()
方法是 promise 并发方法之一。在你有多个不依赖于彼此成功完成的异步任务时,或者你总是想知道每个 promise 的结果时,使用 Promise.allSettled() 。
相比之下,如果任务相互依赖,或者如果你想在任何 promise 被拒绝时立即拒绝,Promise.all() 返回的 Promise 可能更合适。
Promise.allSettled([
Promise.resolve(33),
new Promise((resolve) => setTimeout(() => resolve(66), 0)),
99,
Promise.reject(new Error("一个错误")),
]).then((values) => console.log(values));
// [
// { status: 'fulfilled', value: 33 },
// { status: 'fulfilled', value: 66 },
// { status: 'fulfilled', value: 99 },
// { status: 'rejected', reason: Error: 一个错误 }
// ]
3、Promise.any()
当输入的任何一个 Promise 兑现时,这个返回的 Promise 将会兑现,并返回第一个兑现的值。当所有输入 Promise 都被拒绝(包括传递了空的可迭代对象)时,它会以一个包含拒绝原因数组的 AggregateError 拒绝。
该方法对于返回第一个兑现的 Promise 非常有用。一旦有一个 Promise 兑现,它就会立即返回,因此不会等待其他 Promise 完成
与 Promise.all() 返回一个兑现值数组不同的是,我们只会得到一个兑现值(假设至少有一个 Promise 被兑现)。此方法对于那些如果我们只需要一个 Promise 被兑现,但不在意哪一个被兑现的情况更有益。请注意另一个区别:该方法在接收到空的可迭代对象时会拒绝,因为实际上,该可迭代对象不包含任何兑现的项。你可以将 Promise.any() 和 Promise.all() 与 Array.prototype.some() 和 Array.prototype.every() 进行比较。
同时,与 Promise.race() 返回第一个敲定(无论是兑现还是拒绝)的值不同的是,该方法返回第一个兑现的值。该方法忽略所有被拒绝的 Promise,直到第一个被兑现的 Promise。
const pErr = new Promise((resolve, reject) => {
reject("总是失败");
});
const pSlow = new Promise((resolve, reject) => {
setTimeout(resolve, 500, "最终完成");
});
const pFast = new Promise((resolve, reject) => {
setTimeout(resolve, 100, "很快完成");
});
Promise.any([pErr, pSlow, pFast]).then((value) => {
console.log(value);
// pFast 第一个兑现
});
// 打印:
// 很快完成
4、Promise.race()
这个返回的 promise 会随着第一个 promise 的敲定而敲定。
当你想要第一个异步任务完成时,但不关心它的最终状态(即它既可以成功也可以失败)时,它就非常有用。
如果可迭代对象中包含一个或多个非 promise 值和/或已敲定的 promise,则 Promise.race() 将以可迭代对象中找到的第一个此类值敲定。
function sleep(time, value, state) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (state === "兑现") {
return resolve(value);
} else {
return reject(new Error(value));
}
}, time);
});
}
const p1 = sleep(500, "一", "兑现");
const p2 = sleep(100, "二", "兑现");
Promise.race([p1, p2]).then((value) => {
console.log(value); // “二”
});
const p3 = sleep(100, "三", "兑现");
const p4 = sleep(500, "四", "拒绝");
Promise.race([p3, p4]).then(
(value) => {
console.log(value); // “三”
// p3 更快,所以它兑现
},
(error) => {
// 不会被调用
},
);
const p5 = sleep(500, "五", "兑现");
const p6 = sleep(100, "六", "拒绝");
Promise.race([p5, p6]).then(
(value) => {
// 不会被调用
},
(error) => {
console.error(error.message); // “六”
// p6 更快,所以它拒绝
},
);