2795. 并行执行 Promise 以获取独有的结果 🔒
2795. 并行执行 Promise 以获取独有的结果 🔒
题目
Given an array functions
, return a promise promise
. functions
is an array of functions that return promises fnPromise.
Each fnPromise
can be resolved or rejected.
If fnPromise
is resolved:
obj = { status: "fulfilled", value: resolved value }
If fnPromise
is rejected:
obj = { status: "rejected", reason: reason of rejection (catched error message) }
The promise
should resolve with an array of these objects obj
. Each obj
in the array should correspond to the promises in the original array function, maintaining the same order.
Try to implement it without using the built-in method Promise.allSettled()
.
Example 1:
Input:
functions = [ () => new Promise((resolve) => setTimeout(() => resolve(15), 100)) ];
Output:
{"t":100,"values":[{"status":"fulfilled","value":15}]}
Explanation:
const time = performance.now(); const promise = promiseAllSettled(functions); promise.then((res) => { const out = { t: Math.floor(performance.now() - time), values: res }; console.log(out); // {"t":100,"values":[{"status":"fulfilled","value":15}]} });
The returned promise resolves within 100 milliseconds. Since promise from the array functions is fulfilled, the resolved value of the returned promise is set to [{"status":"fulfilled","value":15}].
Example 2:
Input:
functions = [ () => new Promise((resolve) => setTimeout(() => resolve(20), 100)), () => new Promise((resolve) => setTimeout(() => resolve(15), 100)) ];
Output:
{ "t":100, "values": [ {"status":"fulfilled","value":20}, {"status":"fulfilled","value":15} ] }
Explanation: The returned promise resolves within 100 milliseconds, because the resolution time is determined by the promise that takes the longest time to fulfill. Since promises from the array functions are fulfilled, the resolved value of the returned promise is set to [{"status":"fulfilled","value":20},{"status":"fulfilled","value":15}].
Example 3:
Input:
functions = [ () => new Promise((resolve) => setTimeout(() => resolve(30), 200)), () => new Promise((resolve, reject) => setTimeout(() => reject('Error'), 100)) ];
Output:
{ "t":200, "values": [ {"status":"fulfilled","value":30}, {"status":"rejected","reason":"Error"} ] }
Explanation: The returned promise resolves within 200 milliseconds, as its resolution time is determined by the promise that takes the longest time to fulfill. Since one promise from the array function is fulfilled and another is rejected, the resolved value of the returned promise is set to an array containing objects in the following order: [{"status":"fulfilled","value":30}, {"status":"rejected","reason":"Error"}]. Each object in the array corresponds to the promises in the original array function, maintaining the same order.
Constraints:
1 <= functions.length <= 10
题目大意
给定一个数组 functions
,返回一个 promise 对象 promise
。functions
是一个返回多个 promise 对象 fnPromise
的函数数组。每个 fnPromise
可以被解析(resolved)或拒绝(rejected)。
如果 fnPromise
被解析:
obj = { status: "fulfilled", value: resolved value }
如果 fnPromise
被拒绝:
obj = { status: "rejected", reason: 拒绝的原因(捕获的错误消息)}
该 promise
应该返回一个包含这些对象 obj
的数组。数组中的每个 obj
应该对应原始函数数组中的多个 promise 对象,并保持相同的顺序。
请在不使用内置方法 Promise.allSettled()
的情况下实现它。
示例 1:
输入:
functions = [ () => new Promise((resolve) => setTimeout(() => resolve(15), 100)) ];
输出:
{"t":100,"values":[{"status":"fulfilled","value":15}]}
解释:
const time = performance.now(); const promise = promiseAllSettled(functions); promise.then((res) => { const out = { t: Math.floor(performance.now() - time), values: res }; console.log(out); // {"t":100,"values":[{"status":"fulfilled","value":15}]} });
返回的 promise 在 100 毫秒内解析。由于函数数组中的 promise 被解析,返回的 promise 的解析值设置为[{"status":"fulfilled","value":15}]。
示例 2:
输入:
functions = [ () => new Promise((resolve) => setTimeout(() => resolve(20), 100)), () => new Promise((resolve) => setTimeout(() => resolve(15), 100)) ];
输出:
{ "t":100, "values": [ {"status":"fulfilled","value":20}, {"status":"fulfilled","value":15} ] }
解释: 返回的 promise 在 100 毫秒内解析,因为解析时间取决于需要最长时间来解析的 promise。由于函数数组中的 promises 被解析,返回的 promise 的解析值设置为[{"status":"fulfilled","value":20},{"status":"fulfilled","value":15}]。
示例 3:
输入:
functions = [ () => new Promise((resolve) => setTimeout(() => resolve(30), 200)), () => new Promise((resolve, reject) => setTimeout(() => reject('Error'), 100)) ];
输出:
{ "t":200, "values": [ {"status":"fulfilled","value":30}, {"status":"rejected","reason":"Error"} ] }
解释: 返回的 promise 在 200 毫秒内解析,因为解析时间取决于需要最长时间来解析的 promise。由于函数数组中的一个 promise 被解析,另一个被拒绝,返回的 promise 的解析值设置为[{"status":"fulfilled","value":30},{"status":"rejected","reason":"Error"}]。数组中的每个对象对应原始函数数组中的 promise,并保持相同的顺序。
提示:
1 <= functions.length <= 10
解题思路
思路一:forEach
创建一个新的
Promise
对象:定义promiseAllSettled
函数,返回一个Promise
,确保在所有functions
数组中的Promise
状态都已确定(无论是成功还是失败)时,统一返回结果。遍历
functions
数组:使用forEach
遍历每个返回Promise
的函数fn
。每个fn
会被调用以创建一个新的Promise
对象。处理每个
Promise
的状态:- 如果
Promise
被解析,则在result
数组中对应位置i
存入{ status: 'fulfilled', value: res }
。 - 如果
Promise
被拒绝,则在result
数组中存入{ status: 'rejected', reason: err }
。 - 不管
Promise
是解析还是拒绝,count
都会增加,用于记录已处理的Promise
数量。
- 如果
检查所有
Promise
是否已处理:- 每次有一个
Promise
的状态确定后,都会检查count
是否等于functions.length
。 - 一旦
count
达到functions.length
,表示所有Promise
状态都已确定,调用resolve(result)
将result
数组传回,以保证promiseAllSettled
解析并返回最终结果。
- 每次有一个
复杂度分析
- 时间复杂度:
O(n)
,其中n
是functions
数组的长度,每个函数调用一次。 - 空间复杂度:
O(n)
,需要存储所有的Promise
结果对象。
思路二:Promise.all
- 定义
promiseAllSettled
函数: 函数接受一个Promise
数组并返回一个新的Promise
,该Promise
会等待所有输入的Promise
完成,无论它们是resolved
还是rejected
。 - 遍历所有
Promise
的状态: 对于每个Promise
,使用.then
和.catch
方法分别处理成功和失败的情况,确保将结果以{ status, value/reason }
格式存储。 - 等待所有
Promise
完成: 使用Promise.all
包裹每个处理后的Promise
,确保所有Promise
状态都被收集后才返回。
复杂度分析
- 时间复杂度:
O(n)
,其中n
是functions
的长度,每个函数调用一次。 - 空间复杂度:
O(n)
,用于存储promises
数组的状态。
代码
/**
* @param {Array<Function>}
* @return {Promise<any>}
*/
var promiseAllSettled = function (functions) {
return new Promise((resolve) => {
let result = [],
count = 0;
functions.forEach((fn, i) =>
fn()
.then((res) => {
result[i] = { status: 'fulfilled', value: res };
count++;
})
.catch((err) => {
result[i] = { status: 'rejected', reason: err };
count++;
})
.then(() => {
if (count == functions.length) {
resolve(result);
}
})
);
});
};
/**
* @param {Array<Function>}
* @return {Promise<any>}
*/
var promiseAllSettled = function (functions) {
const promises = functions.map((fn) =>
fn().then(
(value) => ({ status: 'fulfilled', value }),
(reason) => ({ status: 'rejected', reason })
)
);
return Promise.all(promises);
};