承诺和 Node.js MongoDB 驱动程序

6
我想向MongoDB驱动程序做出承诺。我编写了以下代码:
var TaskBroker = function () {
  this.queueName = 'task_queue';
  this.rabbit = {};
  this.mongo = {};
};

TaskBroker.prototype.connectRabbit = function() {
  var self = this;

  return amqp.connect('amqp://localhost')
    .then(function(connection) {
      self.rabbit.connection = connection;
      return connection.createChannel()
    })
    .then(function(channel) {
      self.rabbit.channel = channel;
      return channel.assertQueue(self.queueName, {durable: true});
    })
};

TaskBroker.prototype.connectMongo = function() {
  console.log('Connect Mongo');
  var self = this;
  var defer = q.defer();
  MongoClient.connect('mongodb://127.0.0.1:27017/test', {}, defer.makeNodeResolver());
  return  defer.promise.then(function(db) {
    self.mongo.db = db;
    console.log('hello');
    return 42;
  });
};

TaskBroker.prototype.connect = function () {
  var self = this;
  return this.connectRabbit()
    .then(self.connectMongo);
};

你知道为什么我调用connect方法时没有输出hello吗?

taskBroker.connect()
  .then(function(result) {
    console.log('Disconnected');
    taskBroker.disconnect();
});

你使用的是哪个 Promise 库? - Florian Margaine
@FlorianMargaine 这是基于makeNoreResolver和旧的deferred模式的Q。 - Benjamin Gruenbaum
我正在使用 Q 库。 - Julio
@Julio,如果你在没有使用Promise的情况下对数据库进行普通的DB调用,它能正常工作吗? - Benjamin Gruenbaum
3个回答

9

手动将API转换为Promise是危险的,我建议使用以下方法:

TaskBroker.prototype._connectMongo = Q.nfcall(MongoClient.connect,
                                             'mongodb://127.0.0.1:27017/test',
                                            {});
TaskBroker.prototype.connectMongo = function(){
   return this._connectMongo().then(function(db){
       console.log("Hello");
       // self.stuff...
       return 42;
   }).catch(function(e){
       console.err("connection error",e); // log the connection error, or handler err
       throw e; // don't mark as handled, propagate the error.
   });
};

使用 Bluebird promises,代码看起来应该是这样的:

var MongoClient = Promise.promisifyAll(require("mongodb").MongoClient);

TaskBroker.prototype.connectMongo = function(){
    return MongoClient.connectAsync().then(... 
        // Bluebird will automatically track unhandled errors        
};

1
谢谢。我将 this._connectMongo() 替换为 this._connectMongo,并将 return this.connectRabbit().then(self.connectMongo); 替换为 return this.connectRabbit().then(self.connectMongo());,现在它像魔法一样正常工作了。 - Julio

7

v2.0.36 版本的 Node.js MongoDB 驱动程序首次引入了对 Promises 的一级支持。

下面是官方文档中的示例:

// A simple query showing skip and limit using a Promise.

var MongoClient = require('mongodb').MongoClient,
  test = require('assert');
MongoClient.connect('mongodb://localhost:27017/test', function(err, db) {

  // Create a collection we want to drop later
  var collection = db.collection('simple_limit_skip_query_with_promise');
  // Insert a bunch of documents for the testing
  collection.insertMany([{a:1, b:1}, {a:2, b:2}, {a:3, b:3}], {w:1}).then(function(result) {

    // Peform a simple find and return all the documents
    collection.find({})
      .skip(1).limit(1).project({b:1}).toArray().then(function(docs) {
        test.equal(1, docs.length);
        test.equal(null, docs[0].a);
        test.equal(2, docs[0].b);

        db.close();
    });
  });
});

默认情况下,创建数据库连接时使用 es6-promise 库,但是您可以在创建连接时覆盖它:

var MongoClient = require('mongodb').MongoClient;

MongoClient.connect('mongodb://localhost:27017/test', {
  promiseLibrary: require('bluebird')
}, function(err, db) {
  // ...

6

MongoDB

处理mongodb驱动程序,我建议使用then-mongo(免责声明:我编写了它)。这相当于mongojs,只不过使用的是promise而不是回调函数。它还允许您将“connect”操作视为同步操作,通过立即返回一个可交互的对象,并在内部等待连接来完成。真正好的地方在于它与官方的mongodb文档匹配,因此您可以使用该文档来了解如何使用它。

通用情况

通常情况下,将不返回promise的API转换为返回promise的API应该使用Promise构造函数。例如:

function readFile(filename, enc){
  return new Promise(function (fulfill, reject){
    fs.readFile(filename, enc, function (err, res){
      if (err) reject(err);
      else fulfill(res);
    });
  });
}

如果您正在使用Q,则应执行以下操作:

function readFile(filename, enc){
  return q.promise(function (fulfill, reject){
    fs.readFile(filename, enc, function (err, res){
      if (err) reject(err);
      else fulfill(res);
    });
  });
}

辅助方法

许多库,包括 Q 在内,提供了特殊的辅助方法来适应 node.js 风格的回调方法以返回 promises。例如:

var readFile = q.denodeify(fs.readFile);

或者使用promise
var readFile = Promise.denodeify(fs.readFile);

如果你想了解如何创建和使用Promise对象的更多信息(而不是特定于Q),我建议你查看https://www.promisejs.org/(免责声明:我撰写了该网站)。

非常感谢您提供这么有建设性的答案。 - Julio

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接