2014-05-15 23 views
5

Tôi đang cố gắng tránh sử dụng gọi lại khi thực hiện truy vấn mongodb. Tôi đang sử dụng mongoskin để thực hiện cuộc gọi như vậy:Node.js hứa hẹn với mongoskin

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

Trong nhiều trường hợp tôi cần phải thực hiện các truy vấn nhiều vì vậy tôi muốn sử dụng thư viện hứa Node.js nhưng tôi không chắc chắn làm thế nào để quấn các chức năng này như lời hứa . Hầu hết các ví dụ tôi thấy là tầm thường đối với những thứ như readFile, tôi đoán trong trường hợp này tôi sẽ cần phải bọc toArray bằng cách nào đó? Điều này có thể được thực hiện hoặc sẽ phải là một cái gì đó được thực hiện bởi mongoskin?

Một ví dụ có thể là bất kỳ bộ callbacks, find/chèn, tìm/tìm/chèn, tìm/cập nhật:

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

Trả lời

4

Bạn có thể promisify toàn bộ mô-đun như vậy với 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); 

Điều này chỉ cần được thực hiện ở một nơi trong một lần trong ứng dụng của bạn, không phải ở bất kỳ đâu trong mã ứng dụng của bạn.

Sau đó bạn chỉ cần sử dụng các phương pháp thông thường, ngoại trừ với các hậu tố Async và không vượt qua callbacks:

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

Vì vậy, một lần nữa, nếu bạn gọi một chức năng như

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

Các phiên bản trả lời hứa hẹn được gọi là:

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

(Lỗi không tự động được ghi lại tự động, do đó bạn không cần phải kiểm tra chúng nếu bạn chỉ đăng nhập)

1

Câu trả lời của Esailija có thể hoạt động nhưng không hiệu quả vì bạn phải chạy db.collection mọi cuộc gọi db duy nhất. Tôi không biết chính xác nó đắt tiền như thế nào, nhưng nhìn vào mã trong mongoskin, nó không tầm thường. Không chỉ vậy, nhưng nó là nguyên mẫu sửa đổi toàn cầu, mà không phải là rất an toàn.

Con đường tôi làm điều này với fibers futures là:

  1. quấn phương pháp thu thập cho mỗi bộ sưu tập
  2. trên nhận kết quả, cho các phương pháp mà trả về một con trỏ quấn method toArray, gọi nó và trả lại kết quả trong tương lai (đối với các phương thức không trả về một con trỏ, bạn không cần phải làm gì khác).
  3. sử dụng tương lai như bình thường

như thế này:

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

Nếu bạn không muốn sử dụng sợi, tôi khuyên bạn nên sử dụng the async-future module, trong đó có một chức năng bọc tốt được xây dựng trong quá .

2

Chỉ cần vấp ở đây với cùng một câu hỏi và không yêu "mong" mongoskin như vậy đã làm một chút đào và tìm thấy monk. Nó được xây dựng trên đầu trang của mongoskin, dọn dẹp API và trả về hứa hẹn cho tất cả các cuộc gọi không đồng bộ. Có lẽ đáng xem cho bất kỳ ai khác đến đây.

Các vấn đề liên quan