node.js (JavaScript) 将 forEach 循环与内部回调同步

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15162049/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 13:43:36  来源:igfitidea点击:

(JavaScript) Synchronizing forEach Loop with callbacks inside

javascriptnode.js

提问by megamoth

I am doing some computations inside a double forEachLoop something like this:

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

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

        /* some complex computations with asynchronous callbacks  */        

    });
});

someFunctionHere();

Is there a way for the Loop to finish first before doing the someFunctionHere( )function? or any way that the program will know if the Loop is finish before continuing to someFunctionHere( )...

有没有办法让 Loop 在执行someFunctionHere( )函数之前先完成?或者程序在继续之前知道循环是否完成的任何方式someFunctionHere( )......

I may be missing some forums but the ones I found did not helped me of what I want to achieve and by the way I am doing this in NodeJS , also I am asking if there are existing libraries that can make this happen.

我可能错过了一些论坛,但我发现的论坛并没有帮助我实现我想要实现的目标,顺便说一下我在 NodeJS 中这样做的方式,我还询问是否有可以实现这一目标的现有库。

I forgot to Add this up or should this be an another question?

我忘了把这个加起来还是应该是另一个问题?

Is there a way to do the iteration synchronously that it will only proceed to the next iteration once the current iteration is done? (Sorry for this)

有没有办法同步进行迭代,只有在当前迭代完成后才会进行下一次迭代?(非常遗憾)

Thanks for any help...

谢谢你的帮助...

回答by Golo Roden

Take a look at async.js, and especially its control flowstatements, such as eachwhilstand until.

看看 async.js,尤其是它的控制流语句,例如eachwhilstuntil

Using async.js you can get what you want to have.

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

In your actual situation what you want is the eachfunction (which has formerly been known as forEach), respectively the eachSeriesfunction which does not run the single iterations in parallel, but in serial (see the documentation for eachSeriesfor details).

在您的实际情况中,您需要的是each函数(以前称为forEach),分别是eachSeries不并行运行单个迭代而是串行运行的函数(有关详细信息,请参阅eachSeries文档)。

To provide an example:

提供一个例子:

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 :-)!');
});

This will iterate over the array of prime numbers and print them in the correct order, one after each other, and finally print out Well done :-)!.

这将迭代素数数组并以正确的顺序打印它们,一个接一个,最后打印出Well done :-)!.

回答by Ted Hopp

You can wrap your callbacks in a count-down closure:

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

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  */

    });
});

If the call-backs have different number of arguments, you can do a little surgery on argumentsinstead of using an explicit callbackArgsparameter.

如果回调具有不同数量的参数,您可以做一些手术arguments而不是使用显式callbackArgs参数。

EDITYour edit clarifies that you want to start each complex computation after the previous calculation completes it's callback. This can also be easily arranged through closures:

编辑您的编辑阐明您希望在前一个计算完成其回调后开始每个复杂计算。这也可以通过闭包轻松安排:

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);

回答by Mohit Chawla

HIGH PERFORMANCE SOLUTION:

高性能解决方案:

There might be a case when you might want/allow to process the array asynchronously/parallely but want a function to be called after all members of forEach have been processed. Example:

在某些情况下,您可能希望/允许异步/并行处理数组,但希望在处理完 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");
});

Hence, this way you perform non-blocking CPU intensive operations.

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

NOTE: When you use eachSeriesfor huge arrays, so many iterative callbacks might overflow the stack.

注意:当您将eachSeries用于大型数组时,如此多的迭代回调可能会溢出堆栈。

Read here: https://github.com/caolan/async#control-flow

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

回答by jony89

For browsers which support Promise (or using polyfill) / nodejs I've implemented my self a sync version of forEach with callbacks, so I'll just share that here..

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

The callback must return a promise..

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

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);
    });
}

回答by Erkam KUCET

let dataObject = {};
Promise.all(objectArray.map(object => {
        return new Promise(resolve => {
            yourFunction(object, anotherParameter).then(returnValue => {
                dataObject[object] = returnValue;
                resolve();
            });
        });
    })).then(() => {
        return dataObject;
    });