node.js 中的异步函数完成后如何运行函数?

Posted

技术标签:

【中文标题】node.js 中的异步函数完成后如何运行函数?【英文标题】:How to run a function after an async function completed in node.js? 【发布时间】:2018-01-16 05:14:35 【问题描述】:

我想在我的async forEach 循环之后运行代码。

myPosts.forEach(function(post) 
    getPostAuthor(post.authorID, function(postAuthor) 
        post.author = postAuthor;
    
);

res.render('index', 
    posts: myPosts
);
res.end();

在上面的代码中,首先 res.render 运行,然后 forEach 填充 post.author

【问题讨论】:

forEach 不是异步的。 getPostAuthor 是。 不,但我敢打赌getPostAuthor() 是。 我的意思是 forEach 中的函数 堆栈溢出时这里有数百个重复项。 【参考方案1】:

映射到 Promises 而不是使用 forEach 进行迭代,然后使用 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();

);

【讨论】:

您应该在.then() 处理程序中显示res.render(),因为这是OP 试图完成的(在异步操作完成后进行渲染)。顺便说一句,我没有投票 - 不知道为什么有人这样做。【参考方案2】:

您可以创建一个 promise 数组,然后使用 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();
);

【讨论】:

您已经完成了 90%,然后您没有将 res.render() 放入 Promise.all() 回调中。【参考方案3】:

您可以通过两种方式做到这一点,您可以制作/使用 Promise 或使用计数方法。

计数方法:

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

【讨论】:

【参考方案4】:

您可以使用像 Async 这样的第三方库。

例子:

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.');
    
);

您的代码应如下所示:

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

【讨论】:

【参考方案5】:

你可以试试async/awaitfor 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();

【讨论】:

【参考方案6】:

使用 async.eachOf 遍历数组并应用异步函数:

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

查看异步文档:https://caolan.github.io/async/docs.html

【讨论】:

以上是关于node.js 中的异步函数完成后如何运行函数?的主要内容,如果未能解决你的问题,请参考以下文章

Node.js 等到异步函数完成,然后继续执行其余代码

node.js 在执行'n'异步回调后执行函数

5Node.js 回调函数

Node.js 回调函数

node js 回调函数

Node.js 回调函数