【问题标题】:Chaining Asynchronous Functions Node.js bluebird mongoskin链接异步函数 Node.js bluebird mongoskin
【发布时间】:2015-06-13 17:42:31
【问题描述】:

我已经阅读了很多关于如何链接异步函数的帖子,但我似乎无法正确理解它!

如标题所示。我正在尝试将 mongoskin 数据库调用链接在一起,这样我就可以分块收集所有信息,然后最终在响应中发送累积的结果。

我有对象用户:

var User = {
       username: 'someusername',
       accounts: [{name: 'account_1'}, {name: 'account_2'}]
   }

对于每个帐户,我需要收集数据,然后在响应中发送累积的数据。所以我使用以下 for 循环来迭代帐户:

var promise = require('bluebird');
var db = require('mongoskin').db('mongodb://localhost/someDB');

for(var x in user.accounts){
   //Fetch account data
   user.accounts[x].accountData = fetchAccountData(user.accounts[x].name);
}

//Finally send the collected response
response.send(user);

函数 fetchAccountData 如下所示:

function fetchAccountData(screen_id){
   db.collection('master')
     .aggregate([
        {$match: {screen_id: screen_id}}
      ], function(err, res){
           if(err)
              return null;
           else{
              console.log('Done', screen_id);
              return res;
          }
     });
 }

我怎样才能将其链接到以下算法:

 start:
      for each account:
           fetchDataForAccount
      Finally:
           Send Response 

【问题讨论】:

    标签: javascript node.js asynchronous promise bluebird


    【解决方案1】:

    您的算法可以使用以下代码实现:

    var Promise = require('bluebird');
    var mongo = require('mongoskin'), db;
    
    Promise.promisifyAll(mongo.Collection.prototype);
    
    db = mongo.db('mongodb://localhost/someDB');
    
    Promise.all(user.accounts.map(function(acct) {
      return fetchAccountData(acct.name).then(function(data) {
        acct.accountData = data;
      });
    }))
    .then(function() {
      response.send(user);
    })
    .catch(function(err) {
      // handle error
    });
    
    function fetchAccountData(screen_id){
       return db
         .collection('master')
         .aggregateAsync([
            {$match: {screen_id: screen_id}}
          ]);
    }
    

    编辑:这是代码的细分

    您需要做的第一件事是确保 aggregate 返回一个 Promise 而不是使用延续(例如回调)。你可以通过使用 bluebird 惊人的 promisification 能力来做到这一点:) 这里我们在 mongo.Collection.prototype 上使用它,这样当 collection() 被调用时,它会返回一个具有 promise 能力的集合实例。然后我们有fetchAccountData returnaggregateAsync 返回的promise,因此客户端可以知道该promise 何时解决。

    接下来,我们映射帐户中的每个帐户,并返回一个承诺,一旦获取帐户数据将其分配给帐户对象,该承诺将被履行。然后我们使用Promise.all,它将返回一个“当数组中的所有项目都完成时”的承诺(来自文档)。

    最后,我们必须使用then() 来“等待”,直到所有返回的promise 都解决了,最后用完整的用户对象发回响应。

    【讨论】:

    • 不错的答案,Promise.map 可能比Promise.all 更可取,也可以在帐户上使用.props,但这很好。 +1
    • 啊,Promise.map 看起来很棒!即使使用 Bluebird,我也倾向于坚持使用原生 API,但我真的应该更多地探索它。
    • 非常感谢您的回复。我会尽快尝试的。
    • 非常感谢。那效果很好。我有一个问题,如果我想链接 mongo 函数,例如 db.collection('').find({}).count() ,我将如何格式化查询?谢谢你
    • np! db.collection('').findAsync({}).then(function() { return collection.countAsync(); }) Promise 总是被解包的,一旦你 promisifyAll 一个对象,它的所有方法都会获得额外的 methodAsync 名称,代表相同的方法,除了它们返回一个 Promise。 bluebird docs 对此有更多信息。
    猜你喜欢
    • 2013-12-25
    • 1970-01-01
    • 2017-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-02
    • 2017-10-24
    相关资源
    最近更新 更多