2014-05-15 93 views
5

我試圖避免使用回調製作mongodb查詢時。我使用mongoskin做出像這樣的呼叫:Node.js承諾與蒙戈金

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

在許多情況下,我需要讓多個查詢,所以我想用Node.js的承諾庫,但我不知道如何包裝這些功能的承諾。我看到的大多數示例對readFile等事情來說都是微不足道的,我猜在這種情況下,我需要以某種方式將數組換成數組?這可以做到或者必須是由蒙戈金實施的東西嗎?

一個例子可以是任何一組回調,發現/插入,找到/發現/插入,查找/更新:

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

回答

4

可以promisify整個模塊,像這樣與藍鳥:

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

這隻需要在應用程序的一個地方一次完成,而不是在應用程序代碼的任何地方完成。

之後,你只需要使用方法通常除了與異步後綴,不通過回調:如此反覆

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

(未捕獲的錯誤會自動記錄,所以如果你只是要記錄它,你不需要檢查它們)

1

Esailija的答案可能會奏效,但它不是非常高效,因爲你必須運行db.collection每一個數據庫調用。我不知道這究竟有多昂貴,但在mongoskin中查看代碼非常重要。不僅如此,它還是全球性的修改原型,這不是很安全。

我這樣做與fibers futures的方法是:

  1. 包裝上接收結果,對於返回遊標包裹指定者方法方法爲每個集合
  2. 的收集方法,調用它並返回導致未來(對於不返回遊標的方法,您不需要做其他任何事情)。
  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,它內置了一個過於良好包裹功能。

2

剛剛在這裏遇到了同樣的問題,不喜歡「promisfying」mongoskin所以做了更多的挖掘,發現monk。它建立在mongoskin之上,整理API併爲所有異步調用返回 承諾。可能值得窺視其他任何登陸這裏的人。