(JavaScript)使用里面的回调同步forEach循环

时间:2013-03-01 16:14:03

标签: javascript node.js

我在双forEach循环中进行一些计算,如下所示:

array.forEach(function(element){
    Object.keys(element).forEach(function(key){

        /* some complex computations with asynchronous callbacks  */        

    });
});

someFunctionHere();

在执行someFunctionHere( )功能之前,Loop是否有办法先完成?或者在继续someFunctionHere( ) ...

之前程序将知道循环是否完成的任何方式

我可能会遗漏一些论坛,但是我找到的论坛并没有帮助我实现我想要实现的目标,而且我在NodeJS中这样做,我也在问是否有现有的库可以实现这一点。

我忘了添加它或者这是另一个问题吗?

有没有办法同步进行迭代,一旦当前迭代完成,它只会进入下一次迭代? (对不起)

感谢您的帮助......

5 个答案:

答案 0 :(得分:44)

查看async.js,尤其是each语句,例如whilst untileach

使用async.js可以得到你想要的东西。

在您的实际情况中,您想要的是forEach函数(以前称为eachSeries),async.eachSeries([ 2, 3, 5, 7, 11 ], function (prime, callback) { console.log(prime); callback(); // Alternatively: callback(new Error()); }, function (err) { if (err) { throw err; } console.log('Well done :-)!'); }); 函数,它不会并行运行单个迭代,但是是连续的(详见control flow)。

举个例子:

Well done :-)!

这将遍历素数数组并以正确的顺序打印出来,一个接一个地打印出来,最后打印出{{1}}。

答案 1 :(得分:6)

您可以将回调包装在倒计时结束中:

var len = array.length;

function countdownWrapper(callback, callbackArgs) {
    callback(callbackArgs);
    if (--len == 0) {
        someFunctionHere();
    }
}

array.forEach(function(element){
    Object.keys(element).forEach(function(key){

        var wrappedCallback = countdownWrapper.bind(callback);
        /* some complex computations with asynchronous WRAPPED callbacks  */

    });
});

如果回调的参数数量不同,您可以在arguments上进行一些手术,而不是使用明确的callbackArgs参数。

编辑您的编辑说明您希望在上一次计算完成回调后启动每个复杂计算。这也可以通过闭包轻松安排:

function complexOp(key, callback) { /* . . . */ }

function originalCallback(...) { /* . . . */ }

function doSomethingElse() { /* . . . */ }

var iteratorCallback = (function (body, callback, completion) {
    var i = 0, len = array.length;
    return function iterator() {
        callback.apply(null, arguments);
        if (++i < len) {
            body(array[i], iterator);
        } else {
            completion();
        }
    };
}(complexOp, originalCallback, doSomethingElse)); 

// kick everything off:
complexOp(array[0], iteratorCallback);

答案 2 :(得分:2)

高性能解决方案:

可能存在这样的情况:您可能希望/允许异步/并行处理数组,但希望在处理完所有forEach成员后调用函数。 示例:

var async = require('async');

async.forEach(array,function(elementOfArray, callback){
    //process each element of array in parallel 
    // ..
    // ..
    // .. 
    callback(); //notify that this iteration is complete
}, function(err){
 if(err){throw err;}
 console.log("processing all elements completed");
});

因此,这种方式可以执行非阻塞CPU密集型操作。

注意:当您对大型数组使用 eachSeries 时,许多迭代回调可能会溢出堆栈。

在这里阅读: https://github.com/caolan/async#control-flow

答案 3 :(得分:2)

对于支持Promise(或使用polyfill)/ nodejs的浏览器,我已经使用回调实现了我自己的forEach同步版本,所以我只是在这里分享..

回调必须返回一个承诺..

function forEachSync(array, callback) {
    let lastIndex = array.length - 1;
    let startIndex = 0;

    return new Promise((resolve, reject) => { // Finish all
        let functionToIterateWith = (currIndex) => {
            if (currIndex > lastIndex) {
                return resolve();
            } else {
                callback(array[currIndex]).then(() => {
                    functionToIterateWith(currIndex + 1);
                }).catch(err => reject(err));
            }
        }

        functionToIterateWith(startIndex);
    });
}

答案 4 :(得分:1)

dirp