Javascript forEach是同步还是异步?

时间:2016-10-02 04:34:31

标签: javascript arrays asynchronous browser foreach

我正在阅读this article here关于在forEach内调用异步函数的问题,我为自己做了一个小实验。虽然它工作正常,但我注意到了一些不是&# 39; t完全符合我的预期...

编辑:注释掉上述文章的引用只是为了误导读者并引起混淆。我主要关注的是一般的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除外),我也尝试使用mapfor来查看我是否得到了不同的结果,但它们都是一样的...
拜托,我需要解释这个....这是预期的行为吗?

注意:我说的是浏览器执行,不是Node.js 这里

&#13;
&#13;
    (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;
&#13;
&#13;

已解决:这是基于我对Javascript语言的偏见。我认为Javascript不会等待forEachfor结束,但它与PHP或Perl等其他语言没有什么不同。它实际上等待循环结束。

  

使用正常的for循环,它将像任何其他语言的正常for循环一样运行。 - khazhyk

编辑:编辑:我找到了确切的答案here

  

循环在Node.js和JavaScript中是同步的,同步代码总是运行完成。因此,如果您没有调用异步函数,您可以放心,您的代码在完成之前不会被中断。

2 个答案:

答案 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]