介绍
JavaScript Promise 是一种强大的异步编程技术,可以优雅地解决回调地狱问题。对于多个异步任务执行完成后再进行处理的情况,我们通常会使用 Promise.all 等方式来处理 Promise 数组。但有时候我们需要对 Promise 数组中的每一个 Promise 都进行相同的操作,这时候就需要使用 forEach 循环。然而,由于 Promise 是异步的,forEach 循环也是同步的,如果我们直接在 forEach 中使用 Promise 会遇到一些问题。
本文将介绍如何在 JavaScript Promise 中安全地使用 forEach 循环,以及使用示例。
问题
先来看一个常见的错误使用方法:
const promises = [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)];
promises.forEach(async (promise) => {
const data = await promise;
console.log(data);
});你可能认为以上代码应该输出 1、2、3,但实际上它只会输出 Promise 对象。
这是因为在 forEach 循环中,Promise 异步操作不会等待执行,而是会立即执行下一个操作。当异步操作执行完毕后,会进入微任务队列等待下一个异步操作的执行。而 forEach 循环遍历完毕后,Promise 的异步操作还没有来得及执行,它就直接输出了 Promise 对象本身。
解决方案
那么,我们该如何在 forEach 循环中使用 Promise 呢?
一种常见的方式是使用 for 循环和 await:
const promises = [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)];
for (let i = 0; i < promises.length; i++) {
const data = await promises[i];
console.log(data);
}但如果长度非常长,这种方式就显得不太优雅了。
另一种方式是使用 Array.prototype.reduce:
const promises = [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)];
await promises.reduce(async (previousPromise, promise) => {
await previousPromise;
const data = await promise;
console.log(data);
}, Promise.resolve());这种方式使用了 reduce 来串行执行 Promise,比较灵活而且易于理解。
不过,还有一种更简单的方式,就是将 Promise.all 和 forEach 相结合:
const promises = [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)];
await Promise.all(promises.map(async (promise) => {
const data = await promise;
console.log(data);
}));这种方式将 Promise.all 和 forEach 结合起来,简单实用。它会先将 Promise 数组映射成一个值的数组,然后使用 Promise.all 来执行全部 Promise,最后再对每一个 Promise 进行操作。
示例
最后,给出一个完整的使用示例:
// www.javascriptcn.com code example
// 延时函数,等待指定秒数后 resolve
const timeout = (ms) => new Promise(resolve => setTimeout(resolve, ms));
// 数组中的每一个元素经过一定的等待时间后,将其加倍
const promiseMultipliers = [1, 2, 3].map(async (number) => {
await timeout(1000); // 等待 1 秒钟
return number * 2;
});
// 将所有的 Promise 以并行的方式执行,然后对每一个 Promise 进行操作
await Promise.all(promiseMultipliers.map(async (promise) => {
const data = await promise;
console.log(data);
}));以上代码使用了 map 和 Promise.all 来同时执行 Promise,并在每个 Promise 完成后进行加倍操作。运行结果为 2、4、6,且需要等待 1 秒钟后才会输出。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d7977fa941bf7134d95313