在我的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
} );