简体   繁体   中英

How to run a function after an async function completed in node.js?

I want to run a code after my 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

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();

});

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();
});

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();
    }
});

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();
    }
});

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(); 

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM