在前端开发中,异步操作是非常常见的。但是,当需要同时执行多个异步操作时,往往会遇到一些问题。例如,如何控制异步操作的数量,如何保证它们按照指定的顺序执行等等。在 ES2021 中,引入了一些新的语言特性,可以帮助我们实现异步多重限制方案,本文将详细介绍这些特性的使用方法。
Promise.allSettled()
Promise.all() 是一个非常常用的方法,可以用来将多个 Promise 实例组合成一个新的 Promise 实例,等待所有的 Promise 实例都执行完成后再返回结果。但是,如果其中某个 Promise 实例出现了错误,整个 Promise.all() 就会失败。在这种情况下,我们就需要使用 Promise.allSettled() 方法。
Promise.allSettled() 方法也可以将多个 Promise 实例组合成一个新的 Promise 实例,但是它不会在任何 Promise 实例失败时立即失败,而是会等待所有的 Promise 实例都执行完成后,返回一个包含每个 Promise 实例执行结果的数组。例如:
// www.javascriptcn.com code example
const promises = [
Promise.resolve('result 1'),
Promise.reject(new Error('error')),
Promise.resolve('result 3')
];
Promise.allSettled(promises)
.then(results => {
console.log(results);
})
.catch(error => {
console.log(error);
});上面的代码中,Promise.allSettled() 方法接收一个包含三个 Promise 实例的数组,其中第二个 Promise 实例会返回一个错误。当所有的 Promise 实例都执行完成后,Promise.allSettled() 方法会返回一个包含三个对象的数组,每个对象都包含了对应 Promise 实例的执行结果。例如:
[
{ status: 'fulfilled', value: 'result 1' },
{ status: 'rejected', reason: Error: error },
{ status: 'fulfilled', value: 'result 3' }
]Promise.any()
Promise.any() 方法也是一个新的语言特性,用于将多个 Promise 实例组合成一个新的 Promise 实例,等待其中任何一个 Promise 实例成功后就返回成功结果。如果所有的 Promise 实例都失败了,Promise.any() 方法就会返回一个 AggregateError 对象,其中包含了所有 Promise 实例的错误信息。例如:
// www.javascriptcn.com code example
const promises = [
Promise.reject(new Error('error 1')),
Promise.resolve('result'),
Promise.reject(new Error('error 2'))
];
Promise.any(promises)
.then(result => {
console.log(result);
})
.catch(error => {
console.log(error);
});上面的代码中,Promise.any() 方法接收一个包含三个 Promise 实例的数组,其中第二个 Promise 实例会返回一个成功结果。当其中任何一个 Promise 实例成功后,Promise.any() 方法就会返回一个成功结果,例如:
result
Promise.race()
Promise.race() 方法也是一个非常常用的方法,用于将多个 Promise 实例组合成一个新的 Promise 实例,等待其中任何一个 Promise 实例成功或失败后就返回对应的结果。例如:
// www.javascriptcn.com code example
const promises = [
new Promise(resolve => setTimeout(() => resolve('result 1'), 1000)),
new Promise(resolve => setTimeout(() => resolve('result 2'), 2000)),
new Promise(resolve => setTimeout(() => resolve('result 3'), 3000))
];
Promise.race(promises)
.then(result => {
console.log(result);
})
.catch(error => {
console.log(error);
});上面的代码中,Promise.race() 方法接收一个包含三个 Promise 实例的数组,其中第一个 Promise 实例会在 1 秒后返回结果。当其中任何一个 Promise 实例成功或失败后,Promise.race() 方法就会返回对应的结果,例如:
result 1
async/await
async/await 是一个非常常用的异步编程语言特性,可以让我们像同步代码一样编写异步代码。在 ES2021 中,async/await 也有了一些新的特性,例如:
Promise.any() 和 Promise.allSettled() 的支持
async/await 支持使用 Promise.any() 和 Promise.allSettled() 方法,例如:
// www.javascriptcn.com code example
async function example() {
const promises = [
Promise.reject(new Error('error 1')),
Promise.resolve('result'),
Promise.reject(new Error('error 2'))
];
try {
const result = await Promise.any(promises);
console.log(result);
} catch (error) {
console.log(error);
}
try {
const results = await Promise.allSettled(promises);
console.log(results);
} catch (error) {
console.log(error);
}
}
example();上面的代码中,example() 函数中使用了 async/await 关键字,同时使用了 Promise.any() 和 Promise.allSettled() 方法来处理多个 Promise 实例。当其中任何一个 Promise 实例成功后,async/await 就会返回对应的结果;当所有的 Promise 实例都执行完成后,async/await 就会返回包含每个 Promise 实例执行结果的数组。
for-await-of 循环
for-await-of 循环是一个新的语言特性,可以用于遍历异步迭代器对象。例如:
// www.javascriptcn.com code example
async function example() {
const asyncIterable = {
[Symbol.asyncIterator]() {
let i = 0;
return {
async next() {
if (i < 3) {
return { value: i++, done: false };
}
return { done: true };
}
};
}
};
for await (const value of asyncIterable) {
console.log(value);
}
}
example();上面的代码中,example() 函数中定义了一个异步迭代器对象 asyncIterable,并使用 for-await-of 循环遍历了它的所有值。当异步迭代器对象还有值时,for-await-of 循环就会执行异步操作,并等待异步操作完成后再进行下一次循环。
示例代码
下面是一个使用 Promise.allSettled() 和 async/await 实现异步多重限制方案的示例代码:
// www.javascriptcn.com code example
async function example() {
const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const limit = 3;
const promises = [];
let index = 0;
while (index < data.length) {
const chunk = data.slice(index, index + limit);
const chunkPromises = chunk.map(async item => {
await new Promise(resolve => setTimeout(resolve, 1000));
return item * 2;
});
promises.push(Promise.allSettled(chunkPromises));
index += limit;
}
const results = await Promise.all(promises);
const flatResults = results.flat();
const values = flatResults
.filter(result => result.status === 'fulfilled')
.map(result => result.value);
console.log(values);
}
example();上面的代码中,example() 函数中定义了一个包含 10 个数字的数组 data,同时定义了一个限制并发数量的变量 limit。在 while 循环中,将数组 data 按照 limit 的数量拆分成多个 chunk,每个 chunk 中的数字都会执行一个异步操作,并返回它的值的两倍。最终,使用 Promise.allSettled() 方法将所有的 chunkPromise 组合成一个 Promise 实例,并使用 Promise.all() 方法等待所有的 Promise 实例都执行完成后,返回每个 Promise 实例执行结果的数组。最后,使用 flat() 和 filter() 方法过滤出成功的 Promise 实例,并将它们的值保存到一个新的数组中。当所有的异步操作执行完成后,会将这个新的数组输出到控制台上。
Source: FunTeaLearn,Please indicate the source for reprints https://funteas.com/post/67d99681a941bf713414671d