async for node.js中的循环
我是新来的这个node.js ..我有点困惑这个callback..在我的应用程序里面一个for循环我打电话给一个asynchronous函数调用,我想我的问题是,在我得到asynchronous调用的响应之前我的for循环得到循环。
我的代码:
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)); }); }
searchfunction代码:
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); })
我想成功执行1searchfunction后执行for循环,我想我必须使用async for循环。请指导我解决此问题。
我已经将您的代码示例简化为以下几行,以便更容易理解概念的解释。
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);
前面的代码的问题是search
function是asynchronous的,所以当循环结束时,没有任何callback函数被调用。 因此, results
列表是空的。
为了解决这个问题,你必须把代码放在callback函数的循环之后。
search(query, function(result) { results.push(result); // Put res.writeHead( ... ) and res.end(results) here });
但是,由于callback函数被多次调用(每次迭代一次),您需要知道所有的callback函数都被调用了。 为此,您需要计算callback的数量,并检查该数字是否等于asynchronous函数调用的数量。
要获取所有键的列表,请使用Object.keys
。 然后,遍历这个列表,我使用.forEach
(你也可以使用for (var i = 0, key = keys[i]; i < keys.length; ++i) { .. }
问题,请参阅循环中的JavaScript闭包 – 简单的实例 )。
这是一个完整的例子:
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(); } }); }); }
注意:上例中的asynchronous代码是并行执行的。 如果函数需要以特定顺序调用,那么可以使用recursion来获得所需的效果:
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);
我所展示的是这些概念,您可以在实现中使用许多(第三方)NodeJS模块之一,例如async 。
你已经正确地诊断了你的问题,这么好的工作。 一旦你调用你的search代码,for循环就保持正确。
我是https://github.com/caolan/async的忠实粉丝,这对我很好。; 基本上,你会最终得到像这样的东西:
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'); });
我希望有帮助!
我喜欢在这种情况下使用recursion模式。 例如,像这样的东西:
// If config is an array of queries var config = JSON.parse(queries.querrryArray); // 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
是一个recursion函数,它将从查询数组中抽出查询元素进行处理。 然后,当查询完成时,callback函数再次调用processQueries
。 processQueries
知道在没有查询时结束。
使用数组来完成这个操作是最简单的,但是可以修改它来处理我想象中的对象键/值。
Node.js
引入的async await
在7.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);
为了这个工作search
function必须返回一个promise
或它必须是async
function
如果它没有返回一个Promise
你可以帮助它返回一个Promise
function asyncSearch(query) { return new Promise((resolve, reject) => { search(query,(result)=>{ resolve(result); }) }) }
然后replace这一行await search(query);
通过await asyncSearch(query);