【问题标题】:How can I run this 3 node.js functions asynchronously using async.js?如何使用 async.js 异步运行这 3 个 node.js 函数?
【发布时间】:2017-12-20 19:52:16
【问题描述】:

我有 3 个函数要异步运行,当它们都完成后运行另一个函数:

app.get('/', function (req, res) {

  var homePosts = {
    newsest: [],
    reviewed: [],
    mostPopuler: [],
    viewed: []
  };

  // fetch newest pages and asign the result to 'homePosts.newest '
  function fetchNewestPages() {
    Post.find({ "type": "public", "featuredImage": { "$exists": true } },"_id title briefDes featuredImage", function (err, posts) {
      if (err) {
        req.flash('error', 'An unknown error was occured.');
        res.redirect('back');
      } else {
        homePosts.newsest = posts;
      }
    }).limit(4).sort( { date : -1 } );
  }

  // fetch most reviewed pages and asign the result to 'homePosts.reviewd '
  function fetchMostReviewedPages() {
    Post.find({ "type": "public", "featuredImage": { "$exists": true } },"_id title briefDes featuredImage", function (err, posts) {
      if (err) {
        req.flash('error', 'An unknown error was occured.');
        res.redirect('back');
      } else {
        homePosts.reviewed = posts;
      }
    }).limit(4).sort( { commentsNumber : -1 } );
  }

  // fetch most popular pages and asign the result to 'homePosts.mostPopuler '
  function fetchMostPopularPages() {
    Post.find({ "type": "public", "featuredImage": { "$exists": true } },"_id title briefDes featuredImage", function (err, posts) {
      if (err) {
        req.flash('error', 'An unknown error was occured.');
        res.redirect('back');
      } else {
        homePosts.mostPopuler = posts;
      }
    }).limit(4).sort( { likesNumber : -1 } );
  }

 // now run all 3 functions and when they are done render home page with the homePosts object which contains proper pages
  async.parallel([

    fetchNewestPages,
    fetchMostReviewedPages,
    fetchMostPopularPages

  ], function (err) { // it doesn't run at all
    if (err) throw err;
    console.log(homePosts);
    res.render("home", {homePosts}); // render home page with the proper pages 
  });


});

希望您了解代码的作用,以下是代码作用的描述:

  1. 有 homePosts 对象,该对象将在主页上显示适当的页面
  2. 然后我们有一个函数将从数据库中获取 4 个最新页面,然后将它们分配给 homePost.newest
  3. 然后是一个函数,它将具有最多 cmets 的 4 个页面分配给 homePost.reviewed
  4. 第三个函数与上述两个函数一样,将最受欢迎的页面分配给 homePost.mostPopular
  5. 现在 async.js 应该完成它的工作,同时运行这 3 个函数,然后使用 homePosts 对象渲染一个主页,这是我有问题的部分

最后一个渲染主页的函数根本没有运行。我的问题在哪里?有什么方法可以同时运行这 3 个函数,然后运行最后一个渲染页面的函数?

更新:

我已经设法以这种方式做到这一点,但它们不是同时运行,而是一个接一个地运行。

// fetch newest pages and asign the result to 'homePosts.newest '
  function fetchNewestPages(cb) {
    Post.find({ "type": "public", "featuredImage": { "$exists": true } },"_id title briefDes featuredImage", function (err, posts) {
      if (err) {
        req.flash('error', 'An unknown error was occured.');
        res.redirect('back');
      } else {
        homePosts.newsest = posts;
        cb();
      }
    }).limit(4).sort( { date : -1 } );
  }

  // fetch most reviewed pages and asign the result to 'homePosts.reviewd '
  function fetchMostReviewedPages(cb) {
    Post.find({ "type": "public", "featuredImage": { "$exists": true } },"_id title briefDes featuredImage", function (err, posts) {
      if (err) {
        req.flash('error', 'An unknown error was occured.');
        res.redirect('back');
      } else {
        homePosts.reviewed = posts;
        cb();
      }
    }).limit(4).sort( { commentsNumber : -1 } );
  }

  // fetch most popular pages and asign the result to 'homePosts.mostPopuler '
  function fetchMostPopularPages(cb) {
    Post.find({ "type": "public", "featuredImage": { "$exists": true } },"_id title briefDes featuredImage", function (err, posts) {
      if (err) {
        req.flash('error', 'An unknown error was occured.');
        res.redirect('back');
      } else {
        homePosts.mostPopuler = posts;
        cb();
      }
    }).limit(4).sort( { likesNumber : -1 } );
  }

  fetchNewestPages(function () {
    fetchMostReviewedPages(function () {
      fetchMostPopularPages(function () {
          res.render("home", {homePosts});
      });
    });
  });

【问题讨论】:

    标签: javascript node.js express asynchronous async.js


    【解决方案1】:

    异步库适用于使用回调的函数。你的都不行。

    要么以回调形式重写它们,要么使用 Promise.all 之类的东西:

    Promise.all(
        [fetchNewestPages,
        fetchMostReviewedPages, 
        fetchMostPopularPages])
            .then(res => console.log(res[0], res[1], res[2]))
             .catch(err => console.log(err))
    

    【讨论】:

    • 我这样做了:Promise.all( [fetchNewestPages, fetchMostReviewedPages, fetchMostPopularPages]) .then(res => console.log(homePosts)) .catch(err => console.log(err))但是 homePosts 是空的,这意味着函数还没有运行。
    • 是否可以通过回调运行这些函数以便我可以使用异步?
    • homePosts 是空的,因为在该示例中数据返回到 res。 Promise.all 返回一组承诺,因此请尝试:Promise.all( [fetchNewestPages, fetchMostReviewedPages, fetchMostPopularPages]) .then((res) => { console.log(res); console.log(res[0]); console.log(res[1]); console.log(res[2]); }) .catch((err) => { console.log(err); })
    • 现在我在使用回调,我现在可以使用异步吗? (请阅读更新)
    【解决方案2】:

    希望对你有帮助

    console.log('start');
    
    // fetch newest pages and asign the result to 'homePosts.newest '
    function fetchNewestPages() {
    console.log('1')
    }
    
    // fetch most reviewed pages and asign the result to 'homePosts.reviewd '
    function fetchMostReviewedPages() {
    console.log('2')
    }
    
    // fetch most popular pages and asign the result to 'homePosts.mostPopuler '
    function fetchMostPopularPages() {
    console.log('3')
    }
    
    
    fetchNewestPages();
    console.log('1 DONE');
    fetchMostReviewedPages();
    console.log('2 DONE');
    fetchMostPopularPages();
    console.log('3 DONE');
    

    我也经常使用间隔。例如,如果我有很多回调并且某些东西突然不同步,那么这个技巧会很好

    var obj = {}
    
    // to somelong stuff here and the result is var result
    var result = 'this was generated in the fictive long process above'
    objectme.obj = result // those object string can be used anywhere in the script realy nice.
    
    clearInterval(testinterval); // <-- do also here a clearinterval
    var testinterval = setInterval(function(){
    
    if (objectme.obj) {
    clearInterval(testinterval);
    //.. the interval only stop here at the if. you can do anything here. also you can make a timeout. This will force the script to run as you wish it
    }
    
    },10000);
    

    非常重要。如果您打算将长代码插入 clearinterval 区域,那么您需要增加间隔时间。如果您插入的代码比间隔时间长,那么您的代码将被执行 2 次。

    但是你应该像第一个例子那样做。因为使用间隔可能非常棘手。

    【讨论】:

    • 我已经像你那样做了,但我必须在最后运行这段代码 setTimeout(function() { res.render("home", {homePosts}); }, 1000);因为我应该等到所有 3 个函数都运行完。但我不想这样做。
    • 对不起,我不明白。如果您使用“;”那么一切都会一个接一个地执行。函数 atend() { res.render("home", {homePosts}); } atend();
    • 没有。它们异步运行,当第一个函数运行时,node.js 将转到下一行。我说的是你的第一种方法不使用间隔。
    【解决方案3】:

    您的问题是您的任何函数中都没有回调参数。请记住,当一个函数的处理完成时,您必须调用回调方法。

    我在实践中所做的是使用async.constant 作为async.waterfallasync.parallel 的第一个方法,并传递要在异步方法中使用的数据。在您的情况下,它可以是所有三种方法的搜索标准。 如果异步方法中不使用数据,那么我只传递一个空的 JS 对象。

    使用async.constant 可以帮助我做两件事。

    1. 传递要在异步方法中使用的数据。
    2. 从传递的对象中的异步方法获取结果。

    在您的情况下,async.constant 方法将具有 homePosts 对象。

        app.get('/', function (req, res) {
    
          // fetch newest pages and asign the result to 'homePosts.newest '
          function fetchNewestPages(data, callback) {
              Post
              .find({ "type": "public", "featuredImage": { "$exists": true } },"_id title briefDes featuredImage")
              .limit(4)
              .sort( { date : -1 } )
              .exec(function (err, posts) {
                 if (err) {
                   //If we pass first parameter as non-null, the control is passed to the last optional callback skipping all other functions in case of async.waterfall and not waiting for other functions to complete in case of async.parallel
                   return callback('An unknown error was occured.');  
                 } else {
                   data['newsest'] = posts; //since homePosts is data object inside this function
                   If this function is completed successfully then we pass first parameter as null (no error) and second parameter as our object. As the strategy is parallel, all three functions will be editing the same object 'homePosts'
                   return callback(null, data);
                 }
              });
          }
    
          // fetch most reviewed pages and asign the result to 'homePosts.reviewd '
          function fetchMostReviewedPages(data, callback) {
              Post
              .find({ "type": "public", "featuredImage": { "$exists": true } },"_id title briefDes featuredImage")
              .limit(4)
              .sort( { commentsNumber : -1 } )
              .exec(function (err, posts) {
                 if (err) {
                   //read comment in first function
                   return callback('An unknown error was occured.');
                 } else {
                   data['reviewed'] = posts; //since homePosts is data object inside this function
                   //read comment in first function
                   return callback(null, data);
                 }
              });
          }
    
          // fetch most popular pages and asign the result to 'homePosts.mostPopuler '
          function fetchMostPopularPages(data, callback) {
              Post
              .find({ "type": "public", "featuredImage": { "$exists": true } },"_id title briefDes featuredImage")
              .limit(4)
              .sort( { likesNumber : -1 } )
              .exec(function (err, posts) {
                 if (err) {
                   //read comment in first function
                   return callback('An unknown error was occured.');
                 } else {
                   data['reviewed'] = posts; //since homePosts is data object inside this function
                   //read comment in first function
                   return callback(null, data);
                 }
              });
          }
    
          var homePosts = {
            newsest: [],
            reviewed: [],
            mostPopuler: [],
            viewed: []
          };
    
          // now run all 3 functions and when they are done render home page with the homePosts object which contains proper pages
    
          async.parallel([
            async.constant(homePosts),
            fetchNewestPages,
            fetchMostReviewedPages,
            fetchMostPopularPages
          ], function (err, data) {
                //once all functions complete their execution and their callback method is called, with or without error, this method will be called. 
                if (err) {
                  req.flash('error', err);
                  res.redirect('back');
                } else {
                  console.log(data);
                  res.render("home", {data}); // render home page with the proper pages 
                }
          });
    });
    

    希望这能解决您的问题并更清楚您的概念。

    【讨论】:

      猜你喜欢
      • 2021-01-15
      • 1970-01-01
      • 2018-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-25
      • 2015-11-12
      • 1970-01-01
      相关资源
      最近更新 更多