我正在阅读this article here关于在虽然它工作正常,但我注意到了一些不是&# 39; t完全符合我的预期... forEach
内调用异步函数的问题,我为自己做了一个小实验。
编辑:注释掉上述文章的引用只是为了误导读者并引起混淆。我主要关注的是一般的Javascript循环,与所引用的文章所讨论的异步函数无关。
在代码中,我有一个像这样的控制台输出:
timer.show('[0] res[' + lastindex + ']: '
+ (typeof res[lastindex] != 'undefined' ? res[lastindex] : 'NA'));
位于循环之后 我认为当它位于环路下方时会立即执行,特别是当阵列相对较大时。
但是,我得到的是:
[created] array with 550000
[1,2,3]
[4,5,6]
[7,8,9]
....
[0] res[549999]: NA (elapsed: 4 msec)
[2] res[549998]: 4949988 (elapsed: 223 msec)
[3] res[549999]: 4949997 (elapsed: 224 msec)
[1] res[549999]: 4949997 (elapsed: 224 msec) <--- HERE
[4] res[549999]: 4949997 (elapsed: 236 msec)
done!
所以,这是我的问题....
为什么我的[1]
输出会等待循环结束?
我在其他浏览器上尝试了代码(我通常使用的Chrome除外),我也尝试使用map
和for
来查看我是否得到了不同的结果,但它们都是一样的...
拜托,我需要解释这个....这是预期的行为吗?
注意:我说的是浏览器执行,不是Node.js 这里
(fn => {
// Just creating a huge array for the test.
let arr = [];
let max = 550000; // This seems appropriate
// for stackoverflow snippet execution.
// (or around 10000000 for my browser)
let n = 1;
for (let i=0; i<max; i++) {
arr.push([n++, n++, n++]);
if ((i + 1) >= max) {
fn(arr);
}
}
})(arr => {
// Now, the test begins!
let timer = simple_timer_factory();
let timer_id = timer.beg();
let size = arr.length;
let lastindex = (size - 1);
console.log('[created] array with ' + size);
console.log(' ' + JSON.stringify(arr[0]));
console.log(' ' + JSON.stringify(arr[1]));
console.log(' ' + JSON.stringify(arr[2]));
console.log(' ....');
let res = [];
// Peeping the last element even before the loop begins.
timer.show('[0] res[' + lastindex + ']: '
+ (typeof res[lastindex] != 'undefined' ? res[lastindex] : 'NA'));
arr.forEach((item, i, arr) => {
res.push(item.reduce((a, b) => {
return a + b;
}));
// The element right before the last.
if (i == (lastindex - 1)) {
timer.show('[2] res[' + i + ']: ' + res[i]);
}
// The last element.
if (i == lastindex) {
timer.show('[3] res[' + i + ']: ' + res[i]);
}
});
// Peeping inside the last element before the loop ends!?
timer.show('[1] res[' + lastindex + ']: '
+ (typeof res[lastindex] != 'undefined' ? res[lastindex] : 'NA'));
// To double make sure, we use "setInterval" as well to watch the array.
let id = window.setInterval(() => {
let lastindex2 = (res.length - 1);
if (lastindex2 >= lastindex) {
window.clearInterval(id);
id = void 0;
timer.show('[4] res[' + lastindex2 + ']: ' + res[lastindex2]);
timer.end(timer_id);
console.log('done!');
}
}, 10);
});
/**
* This has nothing to do with the main question here.
* It will keep track of the time elapsed.
* @returns {Object}
*/
function simple_timer_factory() {
var init, prev, curr;
return Object.create({
beg(fn) {
init = prev = curr = Date.now();
( window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
function(tick){
return window.setTimeout(
tick, Math.ceil(1000 / 30)
);
}
)(fn || function(){});
},
snapshot() {
curr = Date.now();
return {
prev,
curr,
elapse: curr - init,
delta: curr - prev
};
},
show(msg) {
console.log(
(msg ? (msg + ' '): '')
+ '(elapsed: '
+ this.snapshot().elapse + ' msec)');
},
end(timer_id) {
prev = curr = void 0;
( window.cancelAnimationFrame ||
window.webkitCancelAnimationFrame ||
function(id){
if (id) {
window.clearTimeout(id);
}
}
)(timer_id);
}
});
}
&#13;
已解决:这是基于我对Javascript语言的偏见。我认为Javascript不会等待forEach
或for
结束,但它与PHP或Perl等其他语言没有什么不同。它实际上等待循环结束。
使用正常的for循环,它将像任何其他语言的正常for循环一样运行。 - khazhyk
编辑:编辑:我找到了确切的答案here。
循环在Node.js和JavaScript中是同步的,同步代码总是运行完成。因此,如果您没有调用异步函数,您可以放心,您的代码在完成之前不会被中断。
答案 0 :(得分:0)
最佳答案在这里 https://stackoverflow.com/a/5050317/7668448
forEach 是阻止同步,它只是 for(){}代码周围的包装器。
forEach 是 Array 原型链的一部分。当像这样someArray.forEach()
进行调用时,内部函数 forEach 将获得指向 someArray 的 this 指针(这就是原型链接的方式)工作)。
我们将一些函数作为参数传递给它,我们通过 this 获得数组,使用for循环遍历该数组,并在每次迭代中调用传递的函数,并使用 for 中的参数和数组。 ====> func.call(this,this [i],i); (在这里,为什么我们首先拥有价值,而在第二个位置拥有索引,可能是相反的hhh (但是这样更好))。
简而言之,这就是ForEach的工作方式。我建议检查一下我指出的所有答案。
答案 1 :(得分:-1)
arr.forEach不是异步的。它在功能上与for循环非常相似,并且在循环结束之前不会返回。
您的代码
timer.show('[0] res[' + lastindex + ']: '
+ (typeof res[lastindex] != 'undefined' ? res[lastindex] : 'NA'));
arr.forEach((item, i, arr) => {
res.push(item.reduce((a, b) => {
return a + b;
}));
// The element right before the last.
if (i == (lastindex - 1)) {
timer.show('[2] res[' + i + ']: ' + res[i]);
}
// The last element.
if (i == lastindex) {
timer.show('[3] res[' + i + ']: ' + res[i]);
}
});
// Peeping inside the last element before the loop ends!?
timer.show('[1] res[' + lastindex + ']: '
+ (typeof res[lastindex] != 'undefined' ? res[lastindex] : 'NA'));
大致等于
timer.show('[0] res[' + lastindex + ']: '
+ (typeof res[lastindex] != 'undefined' ? res[lastindex] : 'NA'));
for (i = 0; i < arr.length; i++) {
item = arr[i];
res.push(item.reduce((a, b) => {
return a + b;
}));
// The element right before the last.
if (i == (lastindex - 1)) {
timer.show('[2] res[' + i + ']: ' + res[i]);
}
// The last element.
if (i == lastindex) {
timer.show('[3] res[' + i + ']: ' + res[i]);
}
}
// Peeping inside the last element before the loop ends!?
timer.show('[1] res[' + lastindex + ']: '
+ (typeof res[lastindex] != 'undefined' ? res[lastindex] : 'NA'));
显然应该在[1]
之前执行[2]和[3]