Reputation: 33
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
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
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
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:
bluebird
library and its amazing Promise.fromCallback
or Promise.promisifyAll
. More here: http://bluebirdjs.com/docs/api-reference.htmlUpvotes: 2
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