为什么 Array.forEach 比 Javascript 中的 for() 循环慢?

IT技术 javascript arrays performance foreach
2021-03-02 10:02:59

谁能告诉我 array.forEach 比 javascript 中的 for 循环慢的原因是什么。有什么特别的原因吗。

这是我试图找到性能的代码。

// Populate the base array
    var arr = [];
    for (var i = 0; i < 1000; i++) {
      arr[i] = i;
    }

    function someFn(i) {
      return i * 3 * 8;
    }

使用 Array.forEach :

arr.forEach(function (item){
  someFn(item);
})

使用 for 循环:

for (var i = 0, len = arr.length; i < len; i++) {
  someFn(arr[i]);
}

我在 test runner 上测试了它。结果如下: 在此处输入图片说明

如您所见,Array.ForEach 比 for 循环慢 96%。提前致谢。

1个回答

根据@BenAston 和@trincot 的反馈更新

粗略地说,这就是两种情况下发生的情况:

For循环

  1. 将索引变量设置为其初始值
  2. 检查是否退出循环
  3. 运行你的循环体
  4. 增加索引变量
  5. 回到第 2 步

每次迭代发生的唯一开销是检查和增量,这是非常低负载的操作。

forEach 循环

  1. 实例化回调函数
  2. 检查是否有下一个元素要处理
  3. 使用新的执行上下文调用要处理的下一个元素的回调(这包括函数的“范围”;因此它的上下文、参数、内部变量和对任何外部变量的引用——如果使用的话)
  4. 运行回调的内容
  5. 回调函数调用拆解
  6. 返回第 2 步

此处第 3 步和第 5 步中函数设置和拆卸的开销远大于为 vanilla for 循环增加和检查整数的开销。

也就是说,许多现代浏览器识别并优化 forEach 调用,在某些情况下,forEach 甚至可能更快!

闭包的创建与forEach自身无关,因为人们可能会传递一个简单的箭头函数,例如x => y += x,它没有闭包。
2021-04-22 10:02:59
“关闭”和“拆卸”对我来说似乎很陌生,您能详细说明一下吗?
2021-05-13 10:02:59
这是一个公平而有趣的问题。是的,创建内联回调可能会影响结果(因为在计时循环中每次重新运行 forEach 时都会重新创建过滤函数)。[].forEach也比其明显的实现慢一个数量级,它的运行速度与 for 循环一样快或快:function forEach(a, fn) { for (var i=0; i<a.length; i++) fn(a[i]); }
2021-05-15 10:02:59
闭包(通过链接更新的答案)使您可以forEach从内部函数(您的回调)访问外部函数的变量(即调用 的任何东西,或者如果不是内联,您已经声明了回调)。为每个调用设置它需要一些 CPU 周期和内存。通过拆卸,我只是指 JavaScript 引擎必须在任何函数调用之后自行清理的额外工作。所有函数调用在开始和结束时都有一些开销,如果没有通过函数内联等方式优化,将会影响性能。
2021-05-18 10:02:59
伟大的!谢谢:) 赞成!
2021-05-19 10:02:59