Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

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..

like image 957
Subburaj Avatar asked Jan 17 '14 11:01

Subburaj


People also ask

Is a for loop async?

For loops. Combining async with a for (or a for...of ) loop is possibly the most straightforward option when performing asynchronous operations over array elements. Using await inside a for loop will cause the code to stop and wait for the asynchronous operation to complete before continuing.

Can you await in a for loop?

You need to place the loop in an async function, then you can use await and the loop stops the iteration until the promise we're awaiting resolves. You could also use while or do.. while or for loops too with this same structure. But you can't await with Array.

How do I use async and await in for loop?

forEach(async (element, index) => { // let result = await element; // console. log(result); // }) // This works well for (const element of myPromiseArray) { let result = await element; console. log(result) } console. log('After For Each Loop') } main();


1 Answers

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. Consequently, the list of results is empty.

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

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.

like image 103
Rob W Avatar answered Sep 30 '22 18:09

Rob W