无法中断的forEach循环和await无效的原因

188 阅读2分钟

事件起因:map循环中使用的await无效

为什么forEach不能中断

forEach 方法设计的初衷是为了简化数组的遍历,并且提供了一种更简洁和函数式的编程风格。它自动处理迭代的细节,例如迭代的起点和终点,并且在每个元素上执行提供的回调函数。然而,由于这种自动化的特性,forEach 方法不提供像传统的 for 循环那样的控制流程(如 breakcontinue)。

为什么forEach 方法无法与 await 关键字一起使用

当在 forEach 循环内部使用 await 关键字时,它不会按预期工作。await 关键字只能在 async 函数内部使用,而 forEach 方法的回调函数是普通函数,而不是异步函数。这意味着 awaitforEach 循环中无法暂停执行,而是会继续同步执行下一项。

回到事件起因:map

map() 方法本身也无法中断循环。即使在回调函数中使用 await,也不能直接中断整个循环。

items.map(async (item) => {
    await someAsyncOperation(item); // 使用 await 暂停异步操作 
    return processItem(item); // 返回处理后的结果 
})
// 在这里想要拿到await的结果是不能保证的 await是失效的

那么如何在map中使用await?

map可以配合Promise.all来实现await

const promises = items.map(async (item) => {
    await someAsyncOperation(item); // 使用 await 暂停异步操作 
    return processItem(item); // 返回处理后的结果 
})
await Promise.all(promises);
// 在这里就能拿到异步操作的结果

for...of 可以被中断的循环如何结合swait使用呢?

for...of 也能结合await使用 不过要注意用法(个人感觉用起来还是稍显麻烦)

const asyncOperation = async (item) => {
  // 模拟异步操作
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log(`处理 ${item}`);
      resolve();
    }, 1000);
  });
};
// 注意这里async写的位置 processArray 返回的是一个promise对象
const processArray = async (array) => {
  for (const item of array) {
    await asyncOperation(item); // 等待异步操作完成
  }
};

// 使用示例
const data = [1, 2, 3, 4, 5];
processArray(data)
  .then(() => {
    console.log('所有异步操作完成');
  })
  .catch((error) => {
    console.error('发生错误:', error);
  });

当然你也可以用更高级的写法: for await...of

for await...of

上面的for...of写法可以写成下面这样

 const processArray = [
    asyncOperation(1),
    asyncOperation(2),
    asyncOperation(3),
    asyncOperation(4),
 ];
 // 要包在async方法里面
 (async function () {
    for await (let p of processArray) {
      console.log(p); // 打印结果:1 2 3 4
    }
 })();

 // processArray 是一个promise数组 是不是让人立刻想到了Promise.all
 Promise.all(processArray).then((value)=>{
    console.log(value); // 打印结果: [1,2,3,4]
 })