嗨,大家好!这里是道长王jj~ 🎩🧙♂️
我们知道 promise 上有许多实例方法,比方说 then()
、 catch()
还有 finally()
,就像小积木一样拼起来,变出一串 promise 链!🔗
我们这次捋一捋 Promise 魔法书里的各种静态方法,看看它们有什么用,怎么用,还能给我们带来什么惊喜!🎉
Promise.resolve()
假设你有一个 promise 对象,刚刚被创建出来的时候,最初始会处于 pending
状态,但是,一旦你在执行器函数里面用 resolve()
或者 reject()
时,最终就会为 fulfilled
或 rejected
。 Promise.resolve()
使我们能够使用我们传递给它的值直接创建一个 fulfilled
promise 对象。
const promise = Promise.resolve( "结束咯" );
console.log( promise );
// Promise { <state>: "fulfilled", <value>: "结束咯" }
在上面的示例中, promise
就会直接达到 fulfilled
状态。
有时候咱们就是懒得折腾,不想费尽心思去写个构造函数、搞个执行器函数什么的, Promise.resolve()
非常方便。只需将值作为输入传递给 Promise.resolve()
,即可返回一个 promise 对象。
Promise.reject()
跟 Promise.resolve()
有点像,这次咱们要聊聊 Promise.reject()
,这个家伙也是个能把 promise 弄成 rejected
状态🐶,我们只需要丢给他原因即可。
const promise = Promise.reject( "发生错误" );
console.log( promise );
// Promise { <state>: "rejected", <value>: "发生错误" }
在上头的例子里,promise
一溜烟就跑进了狗带
状态,根本没进过犹豫不决的 pending
状态。
Promise.all()
大家都知道,我们可以对数组甚至字符串进行循环和迭代。然而,对于 JavaScript 对象,我们无法以相同的方式操作。但是在 ES6 中,我们迎来了可迭代协议,这意味着只要一个对象以特定方式构造,它就可以像数组一样被迭代。当然,我不打算在这篇文章中详细探讨可迭代对象的所有细节📚
好,接下来说说 Promise.all()
吧!为了方便起见,我们只讨论将一系列 promise 作为 Promise.all()
的输入情况。
Promise.all()
会返回一个崭新的 promise
。当所有输入的 promise
都变成 resolved 状态时,这个返回的 promise
也会变成 resolved。但如果有任何一个输入的 promise
被 rejected,那么这个返回的 promise
也会被拒绝。这就是 Promise.all()
在管理多个相互依赖的异步操作时显得十分便捷的原因。
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
const promise1 = delay(1000).then(() => 1);
const promise2 = delay(2000).then(() => 2);
const returnedPromise = Promise.all([promise1, promise2]);
console.log("初始化状态:", returnedPromise); // pending
promise1.then(() => {
console.log("promise1执行完后", returnedPromise); // pending
});
promise2.then(() => {
console.log("promise2执行完后:", returnedPromise); // fulfilled , [ 1, 2 ]
});
在上面的示例中,promise1
会在 1 秒后变成 resolved,值为 1。然而,来自 Promise.all()
的 returnedPromise
目前还没有完成。它等待着数组中的 promise2
也变成 resolved。当 promise2
在 2 秒后变成 resolved,值为 2,那么 returnedPromise
也会变成 resolved。此时,returnedPromise
的值是输入的各个 promise
值的数组,对于这个例子来说是 [1, 2]
。
让我们看一个被拒绝的情况。🙅♂️
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
const promise1 = delay(1000).then(() => 1);
const promise2 = delay(2000).catch(() => "出错了");
const promise3 = delay(3000).then(() => 3);
const returnedPromise = Promise.all([promise1, promise2, promise3]);
console.log("初始化状态:", returnedPromise); // pending
promise1.then(() => {
console.log("promise1执行完后:", returnedPromise);// pending
});
promise2.catch(() => {
console.log("promise2执行完后:", returnedPromise); // rejected, 出错了
});
promise3.then(() => {
console.log("promise3执行完后:", returnedPromise); // rejected, 出错了
});
在上面的例子中,promise1
会在 1 秒后变成 resolved。此时,returnedPromise
仍然保持着 pending 状态,因为它在等待 promise2
和 promise3
的状态。但是,promise2
却被拒绝了。这导致 returnedPromise
也被拒绝,拒绝的原因与 promise2
相同。
此外,Promise.all()
不会等待 promise3
的完成。一旦它在输入的 promise 中遇到了拒绝,Promise.all()
就会立即将返回的 promise 拒绝。这也就是为什么我们说在 Promise 的世界里,Promise.all()
会在遇到拒绝的输入 promise 时“短路”。🏃♂️
Promise.allSettled()
这个函数与 Promise.all()
非常类似,但它走得更远。实际上,Promise.allSettled()
会等待所有异步操作都结束,这意味着返回的 promise
会等待每个输入的 promise
都被解决。即使其中一个输入的 promise
被拒绝,返回的 promise
仍然会等待其他的 promise
结束,然后再自行结算。这就是为什么 Promise.allSettled()
特别适用于管理多个不相互依赖的异步操作的原因。🕒
Promise.allSettled()
也会接受一个可迭代的变量或数组作为输入,并返回一个崭新的 promise
。
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
const promise1 = delay(1000).then(() => 1);
const promise2 = delay(2000).catch(() => "出错了");
const promise3 = delay(3000).then(() => 3);
const returnedPromise = Promise.allSettled([promise1, promise2, promise3]);
console.log("初始化状态:", returnedPromise); // pending
promise1.then(() => {
console.log("promise1执行完后:", returnedPromise); // pending
});
promise2.catch(() => {
console.log("promise2执行完后:", returnedPromise); // pending
});
promise3.then(() => {
console.log("promise3执行完后:", returnedPromise); // fulfilled
// [
// { "status": "fulfilled", "value": 1 },
// { "status": "rejected", "reason": "出错了" },
// { "status": "fulfilled", "value": 3 }
// ]
});
在上面的示例中,注意当 promise2
被拒绝时,returnedPromise
并没有被拒绝。相反,它会等待 promise3
完成。当这三个 promise 都结束时,returnedPromise
才会实现。还要注意,returnedPromise
的值与 Promise.all()
的情况不同。这里返回的值不是一个简单的包含每个 resolved promise 值的数组,而是一个对象数组。数组中的每个对象按照相同的顺序表示每个输入 promise 的状态。如果 promise 被 resolved,对象中会有 status
和 value
属性;如果 promise 被 rejected,则包含 status
和拒绝的 reason
。
所以,在 Promise.allSettled()
中,返回的 promise 总是会被实现。即使所有输入 promise 都被拒绝,返回的 promise 也会通过对象数组来表示每个被拒绝的 promise。
如果我们将一个空数组传递给 Promise.allSettled()
,它的行为就类似于 Promise.all()
,它会(同步地)返回一个已经实现的 promise,其值是一个空数组。在其他所有情况下,返回的 promise 最初都会是挂起状态,并在异步地完成。🌈
Promise.race()
这个函数的操作正如其名,它把输入的 promise 视为参加一场比赛,首先解决的 promise 就是赢家。在这里,胜利意味着 Promise.race()
不会等待其他 promise 的解决。一旦第一个输入 promise 被解决,返回的 promise 就会立即以与第一个解决的 promise 相同的值实现,或者如果它被拒绝,就会拒绝并具有相同的原因。🏆
Promise.race()
也可以接受一个可迭代变量或数组作为输入,并返回一个崭新的 promise。
const promise1 = Promise.resolve(1);
const promise2 = new Promise(resolve => setTimeout(() => resolve(2), 1000));
const returnedPromise = Promise.race([promise1, promise2]);
promise1.then(() => {
console.log("promise1执行完后:", returnedPromise); // fulfilled, 1
});
在上面的例子中,由于 promise1
已经解决,所以 Promise.race()
不会等待 promise2
完成,returnedPromise
会立即以与 promise1
相同的值实现。
如果我们将上面的例子中的 Promise.resolve()
替换为 Promise.reject()
,那么 promise1
将被拒绝,但仍然是第一个解决的输入 promise。因此,returnedPromise
将被拒绝,其拒绝原因与 promise1
相同。
如果我们将一个空数组传递给 Promise.race()
,返回的 promise 将永远保持在 pending
状态,因为没有任何输入 promise 会率先解决,也就无法决定返回的 promise 是 resolved 还是 rejected。🚦
Promise.any()
这个函数和 Promise.race()
非常相似,唯一的区别是 Promise.race()
等待第一个输入 promise 解决,而 Promise.any()
则等待第一个输入 promise 被 fulfilled
。一旦有输入 promise 被实现,Promise.any()
将不再等待其他 promise 的实现。
返回的 promise 会以与第一个已实现的输入 promise 相同的值实现。与 Promise.race()
不同的是,Promise.any()
会忽略所有被拒绝的输入 promise,它会一直等待,直到第一个 promise 被实现。如果没有任何 promise 被实现,或者所有 promise 都被拒绝,Promise.any()
将抛出一个 AggregateError
(Error
的子类),它会将所有单独的错误组合在一起。🌸
🎉 你觉得怎么样?这篇文章可以给你带来帮助吗?当你处于这个阶段时,你发现什么对你帮助最大?如果你有任何疑问或者想进一步讨论相关话题,请随时发表评论分享您的想法,让其他人从中受益。🚀✨