【问题标题】:Node.js promises with mongoskinNode.js 承诺与 mongoskin
【发布时间】:2014-07-04 10:47:32
【问题描述】:

我试图在进行 mongodb 查询时避免使用回调。我正在使用 mongoskin 来拨打电话:

req.db.collection('users').find().toArray(function (err, doc) {
  res.json(doc);
});

在许多情况下,我需要进行多个查询,因此我想使用 Node.js 的 promise 库,但我不确定如何将这些函数包装为 promise。我看到的大多数示例对于readFile 之类的东西都是微不足道的,我猜在这种情况下我需要以某种方式包装 toArray?这可以做到还是必须由 mongoskin 实现?

一个例子可以是任何一组回调,find/insert、find/find/insert、find/update:

req.db.collection('users').find().toArray(function (err, doc) {
  if (doc) {
    req.db.collection('users').find().toArray(function (err, doc) {
      // etc...
    });
  }
  else {
    // err
  }
});

【问题讨论】:

    标签: node.js mongodb express promise mongoskin


    【解决方案1】:

    你可以用 bluebird 像这样承诺整个模块:

    var Promise = require("bluebird");
    var mongoskin = require("mongoskin");
    Object.keys(mongoskin).forEach(function(key) {
      var value = mongoskin[key];
      if (typeof value === "function") {
        Promise.promisifyAll(value);
        Promise.promisifyAll(value.prototype);
      }
    });
    Promise.promisifyAll(mongoskin);
    

    这只需要在您的应用程序中的一个地方完成一次,而不是在您的应用程序代码中的任何地方。

    之后,您只需正常使用方法,除了带有 Async 后缀的方法,并且不传递回调:

    req.db.collection('users').find().toArrayAsync()
      .then(function(doc) {
        if (doc) {
          return req.db.collection('users').find().toArrayAsync();
        }
      })
      .then(function(doc) {
        if (doc) {
          return req.db.collection('users').find().toArrayAsync();
        }
      })
      .then(function(doc) {
        if (doc) {
          return req.db.collection('users').find().toArrayAsync();
        }
      });
    

    同样,如果你调用像

    这样的函数
    foo(a, b, c, function(err, result) {
        if (err) return console.log(err);
        //Code
    });
    

    返回承诺的版本被称为:

    fooAsync(a, b, c).then(...)
    

    (未捕获的错误会自动记录,因此如果您只是要记录它,则无需检查它们)

    【讨论】:

      【解决方案2】:

      刚刚在这里偶然发现了同样的问题,不喜欢“有前途的”mongoskin,所以做了更多的挖掘,发现了monk。它建立在 mongoskin 之上,整理 API 并返回 对所有异步调用的承诺。可能值得一看其他登陆这里的人。

      【讨论】:

        【解决方案3】:

        Esailija 的答案可能有效,但效率不高,因为您必须在每个 db 调用上运行 db.collection。我不知道这到底有多贵,但看看 mongoskin 中的代码,它的重要性不言而喻。不仅如此,它还在全局修改原型,这不是很安全。

        我使用fibers futures 的方式是:

        1. 为每个集合包装集合方法
        2. 在接收到结果时,对于返回 Cursor 的方法包装 toArray 方法,调用它并返回结果未来(对于不返回游标的方法,您无需执行任何其他操作)。李>
        3. 像往常一样使用未来

        像这样:

        var Future = require("fibers/future")
        
        // note: when i originally wrote this answer fibers/futures didn't have a good/intuitive wrapping function; but as of 2014-08-18, it does have one
        function futureWrap() {
            // function
            if(arguments.length === 1) {
                var fn = arguments[0]
                var object = undefined
        
            // object, methodName
            } else {
                var object = arguments[0]
                var fn = object[arguments[1]]
            }
        
            return function() {
                var args = Array.prototype.slice.call(arguments)
                var future = new Future
                args.push(future.resolver())
                var me = this
                if(object) me = object
                fn.apply(me, args)
                return future
            }
        }
        
        var methodsYouWantToHave = ['findOne', 'find', 'update', 'insert', 'remove', 'findAndModify']
        var methods = {}
        methodsYouWantToHave.forEach(function(method) {
            internalMethods[method] = futureWrap(this.collection, method)
        }.bind(this))
        
        // use them
        var document = methods.findOne({_id: 'a3jf938fj98j'}, {}).wait()
        var documents = futureWrap(methods.find({x: 'whatever'}, {}).wait(), 'toArray')().wait()
        

        如果你不想使用光纤,我建议使用the async-future module,它也内置了很好的 wrap 功能。

        【讨论】:

          猜你喜欢
          • 2016-05-12
          • 2018-04-05
          • 2017-05-17
          • 1970-01-01
          • 2015-04-15
          • 1970-01-01
          • 2018-05-29
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多