【问题标题】:Is foreach guaranted to loop in the same order everytime over the same data set?foreach 是否保证每次在相同的数据集上都以相同的顺序循环?
【发布时间】:2019-05-01 23:03:48
【问题描述】:

foreach (Array.prototype.forEach) 是否保证每次在同一数据集上都以相同的顺序循环?为什么?

【问题讨论】:

  • 什么循环和什么对​​象?
  • 因为forEach不是异步的?仅当上一次迭代完成时才接受下一个参数。当然,如果您没有在该循环中调用任何异步函数。
  • 你的意思是Array.prototype.forEach?你说的“为什么”是什么意思?
  • 当然,但是如果提供给它的函数对值进行了一些异步处理,则不能保证该处理以任何特定顺序发生。 [1, 2, 3, 4, 5].forEach((n) => setTimeout(() => console.log(n), Math.random() * 1000))
  • @jonrsharpe 我的意思是我想了解这两种情况下订单逻辑背后的原因。

标签: javascript loops foreach iteration sequence


【解决方案1】:

如果实现遵循标准,那么是的,forEach 按顺序处理数组,但忽略未初始化值的稀疏数组除外。 forEach()the spec 中描述:

forEach 为数组中存在的每个元素按升序调用一次 callbackfn。 callbackfn 仅对实际存在的数组元素调用;数组的缺失元素不会调用它。

它循环遍历从以下开始的索引:

设 lenValue 为使用参数“length”调用 O 的 [[Get]] 内部方法的结果 让 k 为 0。
重复,而 k ...
将 k 增加 1

在 javascript 数组中 对象,并具有 length 属性和作为索引的整数键。规范说它将从k=0 开始,并以k < length 的递增顺序调用arr[k]。它将为 arr 具有属性 k 的所有值调用回调

forEach 忽略元素的稀疏数组示例可能如下所示:

let a  = Array(10)
a[5] = "Five"
a[9] = "Nine"
console.log(a)
// ignores initialized values:
a.forEach((item) => console.log(item))

如果您在回调内部执行异步操作,则可能会出现回调没有按顺序发生,但它仍然是。

根据评论编辑:

您可以通过一些小技巧将一个看起来像数组的对象传递给forEach(它有一个长度和整数键)。 forEach 将按 index 顺序调用项目,而不是它们在对象上定义的顺序。例如:

// an object that has enough info
// for forEach to use
let o = {
    3: "three",
    2: "two",
    0: "zero",
    1: "one",

    length: 4
}

// calls in order of indexes, not order keys were defined
Array.prototype.forEach.call( o, (i) => console.log(i))

【讨论】:

  • 它真的是“按升序”循环还是按照对象的每个元素已定义的顺序循环
  • @Xsmael 请参阅编辑以获取边缘案例示例。 forEach 按键的升序调用,在数组的情况下是索引。
【解决方案2】:

是的,forEach 将等待上一项完成后再处理下一项

//Sync methods;
[1,2,3].forEach(function(e){
    console.log(e)
});
//Output:
//1
//2
//3

如果您在循环中使用异步方法它们将按顺序调用,但循环不会等待回调。

//Async Methods
[1,2,3].forEach(function(e){
    someAsyncMethod(e, console.log);
});
//Output example:
//3
//1
//2

这个answer 有一些方法可以在foreach 中使用异步函数。

至于为什么,有一个叫做ECMAScript的国际标准,所有的JavaScript实现都应该遵守它; Array.prototype.forEach() 的行为在本标准中有所规定。

您可以在ECMAScript® 2018 Language Specification 找到Array.prototype.forEach() 的规范和伪代码

【讨论】:

    猜你喜欢
    • 2020-03-31
    • 2013-08-20
    • 2011-09-29
    • 2017-01-05
    • 1970-01-01
    • 1970-01-01
    • 2019-09-22
    • 2018-09-08
    相关资源
    最近更新 更多