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);
};
