简体   繁体   English

node.js 中的异步 for 循环

[英]async for loop in node.js

I am new to this node.js ..I am little bit confused about this callback..In my app inside a for loop i am calling a asynchronous function call,i think my problem is that before i am getting response of async call my for loop get looped.我是这个 node.js 的新手..我对这个回调有点困惑..在我的应用程序中的 for 循环中,我正在调用异步函数调用,我认为我的问题是在我收到异步调用的响应之前for 循环被循环。

My code:我的代码:

async.forEach(Object.keys(config), function(key, next) {
        search(config[key].query, function(err, result) { // 
        console.log("fffffffffff="+ util.inspect(result))-------- >>>Getting undefined..
            if (err) return next(err) // 
            var json = JSON.stringify({
                "result": result
            });
            results[key] = {
                "result": result
            }
            console.log("rrrrrrrr="+util.inspect(results[key]))
            next() // <---- critical piece.  This is how the forEach knows to continue to the next loop.  Must be called inside search's callback so that it doesn't loop prematurely.                   
        })
    },
    function(err) {
        console.log('iterating done');

         res.writeHead(200, {
        'content-type': 'application/json'
    });
    res.end(JSON.stringify(results));  
    });


}

Search function code:搜索功能代码:

var matches = [];
    var qrySubString = query.substring(0, 4);
    client.query("select * from xxxxxxxxx where level4 ILIKE '%" + query + "%'", function(err, row1, fields) {
        for (var id in row1.rows) {                
            var match, name;                
            if (query == row1.rows[id].level4) {
                match = true;
                name = row1.rows[id].level4;
            }
            else {
                match = false;
                name = query;
            }
            matches.push({
                "id": id,
                "name": row1.rows[id].level4,
                "score": 100,
                "match": match,
                "type": [{
                    "id": "/people/presidents",
                    "name": "US President"
                }]
            })
        }           
        callback(matches);
    })

I want to execute for loop after successful execution of 1 search function,I think i have to use async for loop.Please guide me to solve this..Thanks in advance..我想在成功执行 1 个搜索函数后执行 for 循环,我想我必须使用 async for 循环。请指导我解决这个问题..提前谢谢..

I've reduced your code sample to the following lines to make it easier to understand the explanation of the concept.我已将您的代码示例缩减为以下几行,以便更容易理解该概念的解释。

var results = [];
var config = JSON.parse(queries);
for (var key in config) {
    var query = config[key].query;
    search(query, function(result) {
        results.push(result);
    });
}
res.writeHead( ... );
res.end(results);

The problem with the previous code is that the search function is asynchronous, so when the loop has ended, none of the callback functions have been called.前面代码的问题是search函数是异步的,所以当循环结束时,没有调用任何回调函数。 Consequently, the list of results is empty.因此, results列表为空。

To fix the problem, you have to put the code after the loop in the callback function.要解决此问题,您必须将代码放在回调函数中的循环之后。

    search(query, function(result) {
        results.push(result);
        // Put res.writeHead( ... ) and res.end(results) here
    });

However, since the callback function is called multiple times (once for every iteration), you need to somehow know that all callbacks have been called.但是,由于回调函数被多次调用(每次迭代一次),您需要以某种方式知道所有回调都已被调用。 To do that, you need to count the number of callbacks, and check whether the number is equal to the number of asynchronous function calls.为此,您需要计算回调的数量,并检查该数量是否等于异步函数调用的数量。

To get a list of all keys, use Object.keys .要获取所有键的列表,请使用Object.keys Then, to iterate through this list, I use .forEach (you can also use for (var i = 0, key = keys[i]; i < keys.length; ++i) { .. } , but that could give problems, see JavaScript closure inside loops – simple practical example ).然后,为了遍历这个列表,我使用.forEach (你也可以使用for (var i = 0, key = keys[i]; i < keys.length; ++i) { .. } ,但这可以给问题,请参阅循环内的 JavaScript 闭包 - 简单的实际示例)。

Here's a complete example:这是一个完整的例子:

var results = [];
var config = JSON.parse(queries);
var onComplete = function() {
    res.writeHead( ... );
    res.end(results);
};
var keys = Object.keys(config);
var tasksToGo = keys.length;
if (tasksToGo === 0) {
   onComplete();
} else {
    // There is at least one element, so the callback will be called.
    keys.forEach(function(key) {
        var query = config[key].query;
        search(query, function(result) {
            results.push(result);
            if (--tasksToGo === 0) {
                // No tasks left, good to go
                onComplete();
            }
        });
    });
}

Note: The asynchronous code in the previous example are executed in parallel.注意:上例中的异步代码是并行执行的。 If the functions need to be called in a specific order, then you can use recursion to get the desired effect:如果函数需要按照特定的顺序调用,那么可以使用递归来达到想要的效果:

var results = [];
var config = JSON.parse(queries);
var keys = Object.keys(config);
(function next(index) {
    if (index === keys.length) { // No items left
        res.writeHead( ... );
        res.end(results);
        return;
    }
    var key = keys[index];
    var query = config[key].query;
    search(query, function(result) {
        results.push(result);
        next(index + 1);
    });
})(0);

What I've shown are the concepts, you could use one of the many (third-party) NodeJS modules in your implementation, such as async .我展示的是概念,您可以在您的实现中使用许多(第三方)NodeJS 模块之一,例如async

You've correctly diagnosed your problem, so good job.你已经正确地诊断出你的问题,干得好。 Once you call into your search code, the for loop just keeps right on going.一旦您调用搜索代码,for 循环就会继续运行。

I'm a big fan of https://github.com/caolan/async , and it serves me well.我是https://github.com/caolan/async 的忠实粉丝,它对我很有用。 Basically with it you'd end up with something like:基本上有了它,你最终会得到类似的东西:

var async = require('async')
async.eachSeries(Object.keys(config), function (key, next){ 
  search(config[key].query, function(err, result) { // <----- I added an err here
    if (err) return next(err)  // <---- don't keep going if there was an error

    var json = JSON.stringify({
      "result": result
    });
    results[key] = {
      "result": result
    }
    next()    /* <---- critical piece.  This is how the forEach knows to continue to
                       the next loop.  Must be called inside search's callback so that
                       it doesn't loop prematurely.*/
  })
}, function(err) {
  console.log('iterating done');
}); 

I hope that helps!我希望这有帮助!

I like to use the recursive pattern for this scenario.我喜欢在这种情况下使用递归模式。 For example, something like this:例如,这样的事情:

// If config is an array of queries
var config = JSON.parse(queries.queryArray);   

// Array of results
var results;

processQueries(config);

function processQueries(queries) {
    var searchQuery;

    if (queries.length == 0) {
        // All queries complete
        res.writeHead(200, {'content-type': 'application/json'});
        res.end(JSON.stringify({results: results}));
        return;
    }

    searchQuery = queries.pop();

    search(searchQuery, function(result) {
        results.push(JSON.stringify({result: result}); 
        processQueries();            
    });
}

processQueries is a recursive function that will pull a query element out of an array of queries to process. processQueries是一个递归函数,它将从要处理的查询数组中提取一个查询元素。 Then the callback function calls processQueries again when the query is complete.然后回调函数在查询完成时再次调用processQueries The processQueries knows to end when there are no queries left. processQueries知道在没有查询时结束。

It is easiest to do this using arrays, but it could be modified to work with object key/values I imagine.使用数组最容易做到这一点,但可以修改它以使用我想象的对象键/值。

Node.js introduced async await in 7.6 so this makes Javascript more beautiful. Node.js7.6引入了async await ,所以这让Javascript更漂亮。

var results = [];
var config = JSON.parse(queries);
for (var key in config) {
  var query = config[key].query;
  results.push(await search(query));
}
res.writeHead( ... );
res.end(results);

For this to work search fucntion has to return a promise or it has to be async function为此, search功能必须返回一个promise或者它必须是async函数

If it is not returning a Promise you can help it to return a Promise如果它没有返回一个Promise你可以帮助它返回一个Promise

function asyncSearch(query) {
  return new Promise((resolve, reject) => {
   search(query,(result)=>{
    resolve(result);
   })
  })
}

Then replace this line await search(query);然后替换这一行await search(query); by await asyncSearch(query);通过await asyncSearch(query);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM