Reputation: 609
Asynchronous programming is so much more difficult than synchronous programming.
Using nodeJS, I am trying the following:
for (var i = 0; i < 10; i++) {
someFunction().then(function() {
// Do stuff
});
}
But I want the loop to continue only when the Do Stuff part has completed.
Any idea how this can easily be achieved...?
Thank you!
Upvotes: 3
Views: 11703
Reputation: 4183
more simple, use:
forEach with await
Example :
var myarray = [1,2,3];
myarray.forEach(async i => {
await someFunction().then(function() {
// Do stuff
});
});
Upvotes: 1
Reputation: 540
I had a similar need where I had to query a paged api until I found a match or iterated through each page. We return the total_count in each call.
const request = require('request-promise');
var total_count;
function findItem(uri, authorization, find_string, start_index, page_size) {
return new Promise((resolve, reject) => {
const options = buildGetOptions(uri, authorization, start_index, page_size);
request(options)
.then((res) => {
const count = JSON.parse(res).total_count;
if (total_count != count) {
total_count = count;
}
if (JSON.parse(res).things.some(s => s.name === find_string)) {
resolve(true);
} else if (start_index >= total_count) {
resolve(false);
} else {
resolve(findItem(uri, authorization, find_string, start_index + page_size, page_size));
}
})
.catch((err) => {
reject(err);
});
});
}
function buildGetOptions(uri, authorization, start_index, page_size) {
return {
method: 'GET',
uri: uri + `?start_index=${start_index}&page_size=${page_size}`,
headers: {
'cache-control': 'no-cache',
'content-type': 'application/json',
'Authorization': authorization
}
};
}
Upvotes: 0
Reputation: 4898
Async programming can be confusing, but most of the confusion can be eliminated if you keep in mind things like callbacks and then
will run at a later time, after the code block they're contained in has already finished.
Promise libraries, async
module, are all attempts to get more control over a program's flow. Here is a good article explaining different approaches, that really helped me understand things by seeing different alternative solutions to the same problem.
A couple of the other answers mention Q.all()
. This works well, if you already have an array of promises.
If you have an array of values, or promises, there is another library that makes this even easier, called bluebird
. It has a method called .map()
that you can use to start a promise chain with an array.
With this approach you don't need to call the asynchronous, promise-returning function, store the returned promise in an array, then pass that array to Q.all
. It saves you some steps.
So, assuming you have an array of just values:
var items = [0,1,2,3,4,5,6,7,8,9];
You can do something like the following:
Promise.map(items, function (item) {
return performAsyncOperation(item);
}, {concurrency: n})
.then(function(allResults){
// 'allResults' now contains an array of all
// the results of 'performAsyncOperation'
})
Note: For this to work as expected, performAsyncOperation
must return a promise
Also note the 3rd argument to Promise.map()
: {concurrency: n}
. With this option specified, bluebird will only allow n
operations to be performed at a time, which can be useful if you have a huge amount of items to process that would overwhelm the system if they were all kicked off at once (network connections, filehandles, etc).
Final note: Here is the bluebird API doc. It's extremely well written with lots of examples, and a great way to explore how promises can help make your life easier.
Hope it helps!!!
Upvotes: 5
Reputation: 1211
The pattern I like to use in these kind of situations is to define a function that calls itself once an async operation has completed. Your example would be in the lines of:
var times = 10;
var current = 0;
(function nextLap() {
if (current >= times) {
return callback();
}
++current;
someFunction()
.then(function() {
// do stuff
nextLap();
})
.catch(callback);
})();
Upvotes: 2
Reputation:
You could chain your promises with reduce
:
array.reduce(function(promise, elt) {
return promise.then(function() { return long_process(elt); });
}, new Promise.resolve());
The result of this expression will be a promise for the sequence of operations having completed. Instead of just invoking the ten asynchronous operations and waiting for them all to finish, this code will wait until the first operation is finished before kicking off the second, if that's important.
Upvotes: 1
Reputation: 76
To expand on Anders' answer, this is how I've handled this in the past with multiple promises that need to be awaited:
var promises = [];
for (var i = 0; i < 10; i++) {
promises.push(someFunction().then(function() {
// Do stuff
})
);
}
Q.all(promises)
.then(function() {
// Do all the things!
})
Upvotes: 5
Reputation: 1336
Use Q.all to wait for all promises to resolve before continuing
Upvotes: 1