I have in my node js app a for loop; inside this loop on each iteration a mysql query can be executed (not always, depends); the query is async and I get the result in the success callback; but I need that each iteration of the for loop waits for the callback to finish (if needed):
function calculate() {
var resArray = [];
//[...]
for (i = 0; i < tables.length; i++) {
if (id !== undefined) {
var queryString = ... //build query
sequelize.query(queryString).success(function(result) { //executes query
id = result[0].id;
//do stuff with id returned by the query
//...
//resArray.push( //push in resArray the result of stuff done above )
});
}
else {
//do other kind of stuff and push result in resArray
}
}
return resArray;
}
If id != undefined, the query is executed but the for loop doesn't wait for the success callback and the function returns an incomplete resArray.
How can I do (or how can I reorganize the code) to make this work? (I'm working with node js and I don't have the possibility to use jQuery).
Thanks to Amadan suggestions i got rid of this using a mixed method (with promises and a counter);
I'm really interested in your opinion about this and if you have suggestions to improve it;
First I've added to the project the q library (npm install q) for using promises. Thanks to q i've been able to wrap sequelize.query (callback-based) within a function that returns a promise; a counter for promises keeps in memory the number of promises still pending and the wrapping function executeQuery decremets it when each promise is resolved;
(the for loop in cycle() function executes 4 loops; it executes 2 times the query and 2 times a simple log; the goal is that the 'finished' log is sent to the screen only after for loop ends and all promises are resolved
------------------ UPDATE ------------------------------------------------------------
Following hugomg suggestion I've updated the code with this that is more clean: I push every promise in an array and then use Q.all to wait for all of them to be resolved
You need to change your way of thinking. If
calculate
calls an asynchronous method, the only way you're getting its results is not byreturn
, but by calling another callback. In node.js, you mustn't think of a function as a black box that takes an input and returns an output; you need to think of it as a step in a process that has a certain future. The question you need to ask yourself is - "I got these results; what then?"Just like with
sequelize.query
, where you tell it "do this query, and then do this with the results", you need to be able to callcalculate
and tell it "go do those queries, and then do this with their results". You're not getting a return fromsequelize.query
- and you shouldn't be trying to return something fromcalculate
, either.Promises would work great, but without relying on them, you can just count. There are four changes in code below:
and then you can replace the hypothetic and non-functional
with
EDIT: put the countdown into
done
handler to account for possible errors.