[英]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.js
在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);
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.