跳至主要內容

2795. 并行执行 Promise 以获取独有的结果 🔒


2795. 并行执行 Promise 以获取独有的结果 🔒

🟠   🔗 力扣open in new window LeetCodeopen in new window

题目

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 对象 promisefunctions 是一个返回多个 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

  1. 创建一个新的 Promise 对象:定义 promiseAllSettled 函数,返回一个 Promise,确保在所有 functions 数组中的 Promise 状态都已确定(无论是成功还是失败)时,统一返回结果。

  2. 遍历 functions 数组:使用 forEach 遍历每个返回 Promise 的函数 fn。每个 fn 会被调用以创建一个新的 Promise 对象。

  3. 处理每个 Promise 的状态

    • 如果 Promise 被解析,则在 result 数组中对应位置 i 存入 { status: 'fulfilled', value: res }
    • 如果 Promise 被拒绝,则在 result 数组中存入 { status: 'rejected', reason: err }
    • 不管 Promise 是解析还是拒绝,count 都会增加,用于记录已处理的 Promise 数量。
  4. 检查所有 Promise 是否已处理

    • 每次有一个 Promise 的状态确定后,都会检查 count 是否等于 functions.length
    • 一旦 count 达到 functions.length,表示所有 Promise 状态都已确定,调用 resolve(result)result 数组传回,以保证 promiseAllSettled 解析并返回最终结果。

复杂度分析

  • 时间复杂度O(n),其中 nfunctions 数组的长度,每个函数调用一次。
  • 空间复杂度O(n),需要存储所有的 Promise 结果对象。

思路二:Promise.all

  1. 定义 promiseAllSettled 函数: 函数接受一个 Promise 数组并返回一个新的 Promise,该 Promise 会等待所有输入的 Promise 完成,无论它们是 resolved 还是 rejected
  2. 遍历所有 Promise 的状态: 对于每个 Promise,使用 .then.catch 方法分别处理成功和失败的情况,确保将结果以 { status, value/reason } 格式存储。
  3. 等待所有 Promise 完成: 使用 Promise.all 包裹每个处理后的 Promise,确保所有 Promise 状态都被收集后才返回。

复杂度分析

  • 时间复杂度O(n),其中 nfunctions 的长度,每个函数调用一次。
  • 空间复杂度O(n),用于存储 promises 数组的状态。

代码

forEach
/**
 * @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);
					}
				})
		);
	});
};