Reputation: 95
I want to run a code after my async forEach loop.
myPosts.forEach(function(post) {
getPostAuthor(post.authorID, function(postAuthor) {
post.author = postAuthor;
}
});
res.render('index', {
posts: myPosts
});
res.end();
in code above first res.render runs and after that forEach fills the post.author
Upvotes: 5
Views: 9515
Reputation: 138267
Rather map to Promises than iterating with forEach, then use Promise.all:
Promise.all(
myPosts.map(function(post) {
return new Promise(function(res){
getPostAuthor(post.authorID, function(postAuthor) {
post.author = postAuthor;
res(postAuthor);
});
});
})
).then(function(authors){
res.render('index', {
posts: myPosts
});
res.end();
});
Upvotes: 6
Reputation: 4678
use async.eachOf to iterate over an array and apply async function :
async.eachOf(myPosts, function(post, it, callback){
// apply async function on each element
getPostAuthor(post.authorID, function(postAuthor) {
post.author = postAuthor;
return callback();
});
}, function(err){
// final callback when flow is finished
res.render('index', {
posts: myPosts
});
return res.end();
});
See async documentation : https://caolan.github.io/async/docs.html
Upvotes: 0
Reputation: 8287
You can create an array of promises, then listen for all completions using Promise.all
.
const promises = [];
myPosts.forEach(function(post) {
const promise = new Promise((resolve) => {
getPostAuthor(post.authorID, function(postAuthor) {
post.author = postAuthor;
resolve(); // complete the current promise
}
});
promises.push(promise);
});
Promise.all(promises).then(() => {
res.render('index', {
posts: myPosts
});
res.end();
});
Upvotes: 4
Reputation: 51
You could try async/await
with for loop
.
const sleep = timeout => new Promise(resolve => setTimeout(() => resolve(), timeout));
const myPosts = [1,2,3];
const fetchPosts = async () => {
for (let post_id of myPosts) {
await sleep(1000); // simulate fetch post
console.log('post:', post_id);
}
console.log('done!');
};
fetchPosts();
Upvotes: 0
Reputation: 90
You could use a third-party lib like Async.
Example:
import each from 'async/each';
var elements = [1, 2, 3, 4, 5, 6];
each(elements, function(el, next) {
console.log('Processing element ' + el);
callAsyncFunction(next); //your async function should accept a callback
}, function(err){
//this is your ending function. It'll be called after all elements have been processed
if( err ) {
console.log('A file failed to process');
} else {
console.log('Async processing is finished.');
}
});
Your code should look like:
each(myPosts, function(post, next) {
getPostAuthor(post.authorID, function(postAuthor) {
post.author = postAuthor;
next()
});
}, function(err) {
if (!err) {
res.render('index', {
posts: myPosts
});
res.end();
}
});
Upvotes: 0
Reputation: 1464
You could do this 2 ways, you could make/use a Promise or use a counting method.
Counting method:
var numComplete = 0;
var done = function() {
if(numComplete >= myPosts.length) {
// Code to run once finished
}
};
myPosts.forEach(function(post) {
getPostAuthor(post.authorID, function(postAuthor) {
post.author = postAuthor;
numComplete++;
done();
}
});
Upvotes: 0