Promise 和 nodejs MongoDB 驱动程序

Posted

技术标签:

【中文标题】Promise 和 nodejs MongoDB 驱动程序【英文标题】:Promise and nodejs MongoDB driver 【发布时间】:2014-06-29 02:36:49 【问题描述】:

我想对 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();
);

【问题讨论】:

你使用的是哪个承诺库? @FlorianMargaine 它是基于 makeNoreResolver 和旧延迟模式的 Q。 我正在使用Qlibrary。 @Julio 如果你执行一个普通的数据库调用而不对数据库做出承诺,它会起作用吗? 【参考方案1】:

手动承诺 API 是危险的,我建议如下:

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 的 promise,它看起来像这样:

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

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

【讨论】:

谢谢。我将this._connectMongo() 替换为this._connectMongo,将return this.connectRabbit().then(self.connectMongo); 替换为return this.connectRabbit().then(self.connectMongo());,现在它就像一个魅力。【参考方案2】:

node mongodb驱动的v2.0.36引入了对promise的一流支持。

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

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

【讨论】:

【参考方案3】:

MongoDB

为了处理 mongodb 驱动,我建议使用then-mongo(免责声明:我写的)。这等效于mongojs,除了使用承诺而不是回调。它还允许您通过立即返回可以与之交互的对象并在内部等待连接来将“连接”操作视为同步操作。真正的好处是它与官方的 mongodb 文档相匹配,因此您可以使用该文档来弄清楚如何使用它。

一般情况

一般来说,获取一个不返回 Promise 的 API 并获取一个返回的 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 样式的回调方法以返回 Promise。例如

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

或promise:

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

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

【讨论】:

感谢您提供非常有建设性的回答。

以上是关于Promise 和 nodejs MongoDB 驱动程序的主要内容,如果未能解决你的问题,请参考以下文章

nodejs中function*yield和Promise的示例

nodejs promise深度解析

NodeJS之Promise

如何在这个nodejs代码中执行和处理promise? (用户前后的排行榜排名)

连接太多 Nodejs + mysql2/promise

Nodejs Promise的一点记录