【JavaScript】forEach 是按数组顺序执行吗?

简单直接的回答是:是的,在同步代码中,forEach 是严格按照数组索引顺序(从 0 到 length-1)执行的。

但这里有一个巨大的陷阱 :虽然它按顺序"启动"任务,但它不会等待异步操作(如 Promise)完成

下面从三个维度详细分析:

1. 同步代码:严格顺序执行

如果你在 forEach 中执行的是纯同步逻辑,它会从头到尾依次执行:

javascript 复制代码
const arr = [1, 2, 3];
arr.forEach(num => {
  console.log(num);
});
// 输出顺序永远是: 1, 2, 3

2. 异步代码:顺序启动,但不顺序等待(最常见的坑)

当你把 async/await 放在 forEach 中时,forEach 不会等待上一个循环的任务完成才开始下一个。

javascript 复制代码
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));

const arr = [1, 2, 3];

async function test() {
  console.log('开始');
  
  arr.forEach(async (num) => {
    await delay(1000 / num); // 不同的延迟时间
    console.log(num);
  });

  console.log('结束');
}

test();

// 实际输出顺序:
// 开始
// 结束
// 3 (延时最短,先完成)
// 2
// 1 (延时最长,最后完成)

原因: forEach 内部的逻辑大致是这样的:for (let i = 0; i < len; i++) { callback(arr[i]); }。它只是简单地调用了回调函数,并没有 await 回调函数的返回值。

3. 特殊规则:跳过"稀疏"位置

forEach 会跳过数组中已删除或未赋值的项(空位),但不会跳过 undefined

javascript 复制代码
const arr = [1, , 3]; // 索引 1 是空位
arr.forEach((num, i) => console.log(i, num));
// 输出:
// 0 1
// 2 3
// (跳过了索引 1)

总结与最佳实践

如果你需要严格按顺序执行异步任务 (即:任务1完成 -> 任务2开始),请不要 使用 forEach,改用以下方式:

方法 A:使用 for...of(推荐)

for...of 能够正确处理 await

javascript 复制代码
for (const num of arr) {
  await doSomethingAsync(num); // 这里会严格等待
}
方法 B:使用 reduce
javascript 复制代码
arr.reduce(async (promise, num) => {
  await promise;
  await doSomethingAsync(num);
}, Promise.resolve());
方法 C:如果你不需要顺序,只需要并发

如果你希望所有任务同时开始 并等待全部结束,使用 map 配合 Promise.all

javascript 复制代码
await Promise.all(arr.map(async (num) => {
  await doSomethingAsync(num);
}));

结论: 在处理同步逻辑时,forEach 是顺序的;在处理 async/await 异步逻辑时,它会导致"并发"执行(实际上是顺序启动,乱序结束),这通常不是你想要的结果。

相关推荐
认真的酒窝3 小时前
自己动手开发编译器(十一)语义分析
java·开发语言
Dxy12393102164 小时前
MySQL索引完整教程:创建、查看、修改、删除与日常管理
前端·javascript·mysql
wbs_scy4 小时前
Linux C++ 高并发编程:线程池全链路深度解析,从原理到手撕实现
java·开发语言
JAVA面经实录9174 小时前
Linux 常用命令完整知识体系
java·linux·开发语言·汇编
贪玩的蛋挞5 小时前
C#与闭包
开发语言·c#
端庄的战斗机5 小时前
javascript 设计模式(文章很长,请自备瓜子,水果和眼药水)
开发语言·javascript·设计模式
Full Stack Developme6 小时前
Java LRU 与 LFU 算法及应用
java·开发语言·算法
C语言小火车7 小时前
C++ 堆排序深度精讲:基于完全二叉树的选择排序进化,最坏情况 O(n log n) 的稳定王者
开发语言·c++·算法·排序算法·堆排序
北冥you鱼7 小时前
abigen 最佳实践:从入门到精通,高效生成 Go 语言合约绑定
开发语言·golang·区块链
前端毕业班8 小时前
uni-app 小程序支持 teleport 了
前端·javascript·vue.js