如果在使用 JavaScript 中的 map 方法执行遍历该数组的循环期间将元素推送到数组上会发生什么情况



在我的Web应用程序中:

  • 我有一个通过火力基础 API 实时更新的数组。
  • 我有一个用户触发的方法,它循环通过该数组到 根据几个给定参数检索元素。

如果在使用 javascript 中的 map 方法执行通过该数组的循环期间将元素推送到数组上会发生什么?

或者换句话说,我是否可以假设在使用 map 方法遍历数组时,map 方法循环遍历数组的快照?

我想避免使用JSON.parse(JSON.stringify(myArray))来确保我正在循环浏览快照。

任何人都可以提供可以测试此方案以获得明确答案的代码吗?

你真的不需要测试这个;ECMAScript 规范很明确:

map 处理的元素范围是在第一次调用 callbackfn 之前设置的。在调用 map 开始后附加到数组的元素不会被 callbackfn 访问。如果数组的现有元素被更改,则传递给 callbackfn 时它们的值将是 map 访问它们时的值;不会访问在调用 Map 开始之后和访问之前删除的元素。

如果你想测试,你可以使用这样的东西:

const arr = [5];
const result = arr.map( x => {
console.log( `Visiting ${x}` );
arr.push( x + 1 );
return 2*x;
} );
console.log( arr ); // Has two elements
console.log( result ); // Only has one element

但是,当您说:

或者换句话说,我是否可以假设在使用 map 方法遍历数组时,map 方法循环遍历数组的快照?

这与你以前的措辞不同。被推送到数组上的元素不会被映射回调访问,但已被替换的元素将成为它们的新值。您可以像这样进行测试:

const arr = [0,0];
const result = arr.map( x => {
console.log( `Visiting ${x}` );
arr[1] = 3;
return 2*x;
} );
console.log( result );

注意:Array#map 是同步的,而 JavaScript 是单线程的,所以如果回调中的代码没有改变数组,那么数组在迭代过程中就不可能变异(其他代码,即 firebase,在 map 运行时无法运行)。

const arr = [0,1,2,3,4,5];
// Change a random value in arr every 4 milliseconds
//    Emulates Firebase modifying the array
setInterval( function ( ) {
arr[~~(Math.random()*6)] = Math.random( );
}, 4 );
// (async), Logs values after they've been modified
setTimeout( function ( ) {
console.log( 'Logging array values after one second' );
arr.map( x => console.log( x ) );
}, 1000 );
// Logs the values unmodified, async code, such as Firebase can't affect this
console.log( '(sync) with a 100ms spinlock between each map callback, to demonstrate that the array cannot be modified externally during the map.' );
arr.map( x => {
console.log( x );
const start = +new Date;
while( +new Date < start + 100 ); // Wait for 100 milliseconds
} );

最新更新