Rasool jahani
Rasool jahani

Reputation: 33

node js wait for a function return to continue a for-loop

I have a for loop which calls a function in every step.

that function calls an API and I don't know how long it takes to get a response.

what I need is to wait until function updatePE() return a value before loop goes to the next step.

 db.query("SELECT * FROM tb_table where active = true;", (err, result) => {
  if (err) {console.log('ERROR'); return; }

for (const key in Object.keys(result.rows)) {

    updatePE(result.rows[key].b,result.rows[key].s,result.rows[key].k);

}
});

Upvotes: 1

Views: 4769

Answers (4)

Sankalpa Timilsina
Sankalpa Timilsina

Reputation: 341

Do it using async library. It lets you go to next iteration of a for loop only after you fire a callback. Like this:

var async = require('async');
async.forEach(Object.keys(result.rows), async function(key, cb) { 
  await updatePE(result.rows[key].b,result.rows[key].s,result.rows[key].k);
  cb();
}, function(err) {
   // Here you know that the loop has completed (with err or success).
});

Be sure to return a promise in you updatePE. Like this:

function updatePE(b, s, k) {
  return new Promise(function(resolve, reject) {
    // Your update code here.
    if(updateSuccessful) resolve();
    else reject();
  });
}

Upvotes: 0

Muhand Jumah
Muhand Jumah

Reputation: 1958

I highly recommend you take a look at the async library, it is a great library for this sort of things.

Now lets talk about your issue and how can it be solved. assuming updatePE is your own function I would convert that function to a promise or add a callback to it, this way you know when it finishes executing.

for example

// Promise implementation
function updatePE(x, y, z) {
   return new Promise(function(resolve, reject){
       // Do your work here and when is done resolve it
       resolve();
   });
}

// Callback implementation
function update(x, y, z, callback)
{
     // Do your work here and when is done, callback
     callback()
}

now using the async library you can do the following

// If your updatePE uses callback
async.forEach(result.rows, function(row, callback) {
     updatePE(x, y, z, function() {
        callback(null)
     });
}, function(err){
     if (err) {
        // Loop is finished with an error
     } else {
        // Loop is finished without an error
     }
});

// If your updatePE uses promise
async.forEach(result.rows, function(row, callback) {
     updatePE(x, y, z)
        .then(function(){
           callback(null)
        })
        .catch(function(err){
           callback(err)
        })
}, function(err){
     if (err) {
        // Loop is finished with an error
     } else {
        // Loop is finished without an error
     }
});

Upvotes: 0

SzybkiSasza
SzybkiSasza

Reputation: 1599

Assuming that your update function is asynchronous (Promise-based) and you can use async/await (at least Node 8.x is needed), you can write your code in a way that all the updates will happen in parallel (from the code standpoint, as in reality NodeJS operates on top of execution queue in single thread):

 // Note "async" keyword added to the function.
 // It means it'll be converted to Promise and its internal implementation
 // can use "await"
 db.query('SELECT * FROM tb_table where active = true;', async (err, result) => {
  if (err) {
    // A good idea - you should throw a proper error here
    console.log('ERROR'); return; 
  }

  // We'll collect all the promises in that array
  const updatePromises = [];
  for (const key in Object.keys(result.rows)) {
    // IMPORTANT NOTE! Updates will start executing here, but we'll
    // Wait for finishing them later
    updatePromises.push(
      updatePE(result.rows[key].b,result.rows[key].s,result.rows[key].k)
    );
  }

  // Here we wait until all the updates are finished
  await Promise.all(updatePromises);

  // Here you can put all your code that should happen *AFTER* updates are finished
});

More on async/await in JS here:

Another thing worth mentioning - your query code uses callbacks, which are considered rather obsolete in modern JS world - please check if your db library exposes Promise interface - It'll simplify your code a lot and provide a consistent way of error handling without a lot of hassle.

If you want to properly use Promises with existing code and you don't use Promise-compatible library, you can either use:

Upvotes: 2

sudo
sudo

Reputation: 943

If updatePE() is a synchronous function, then It will wait for the return of that function call, if its an async function then try to put await in front of that that will until the function returns

await updatePE() //make sure updatePE() is an async function

like this

async function updatePE(param1, param2, param3){
  return new Promise((resolve, reject)=>{
    //do something and call 
    //resolve(true)
  })
}

Make sure you can call await inside an async function only, so caller function needs to be async as well

(async function(){
 db.query("SELECT * FROM tb_table where active = true;", (err, result) => {
  if (err) {console.log('ERROR'); return; }
  for (const key in Object.keys(result.rows)) {
    await updatePE(result.rows[key].b,result.rows[key].s,result.rows[key].k);
  }
 });
})()

Upvotes: 0

Related Questions