【发布时间】:2017-02-10 08:27:52
【问题描述】:
我正在阅读 this article here 关于在 虽然效果很好,但我注意到一些与我不太一样的东西预计...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);
}
});
}
已解决:这是基于我对 Javascript 语言的偏见。我认为 Javascript 不会等待 forEach 或 for 结束,但它与 PHP 或 Perl 等其他语言没有什么不同。它实际上是在等待循环结束。
使用普通的 for 循环,它将像任何其他语言的普通 for 循环一样运行。 – 哈日克
编辑:编辑:我找到了确切的答案here。
循环在 Node.js 和 JavaScript 中是同步的,同步代码始终运行到完成。因此,如果您不调用异步函数,您可以放心,您的代码在完成之前不会被中断。
【问题讨论】:
-
“为什么我的 [1] 输出要等待循环结束?” 不能正确解释问题。预期的结果是什么?
-
.forEach()本身并不是异步的。它的function参数是一个迭代器而不是一个回调。而且,您的示例不会反过来调用任何异步函数,就像本文所讨论的那样。 -
您可以尝试除
console之外的其他方法来打印输出吗?或将结果推送到数组并在循环后记录。console.log可以在浏览器优化中出人意料地工作。 -
请注意,在您链接的问答中讨论的
async.forEach()(现为async.each())与Array'sforEach()method 的功能不同。两者都不是异步的,但前者更适合与它一起使用的异步操作。 -
谢谢大家。好吧,我知道引用的文章是关于
async库的,我可能不应该首先引用这篇文章......我正在讨论一般的forEach并且甚至没有尝试调用任何外部异步函数.很抱歉模棱两可......所以,问题是,为什么循环外的console.log(循环右下方)不是在循环期间而是在循环执行之后执行?目前,我接受了 sabithpocker 的建议,并没有使用console.log编写代码,但结果保持不变......
标签: javascript arrays asynchronous browser foreach