需要模块的异步问题

时间:2014-08-22 16:24:34

标签: node.js promise

我正在尝试创建一个mongoClient连接池模块以在我的项目中使用。问题是我第一次加载页面并调用mongoFactory时,似乎我的mongoConnection尚未建立。之后每隔一段时间我加载页面就可以了。不知道我在这里缺少什么..

这是我的mongoFactory.js

/**
 * Creates and manages the Mongo connection pool
 *
 * @type {exports}
 */
var constants = require('../js/constants.js');
var Q = require('q');
var MongoClient = require('mongodb').MongoClient;
var db = null;

var getDb = function() {

  console.log('db = '+db);
  // If the connection pool has not been created or has been closed, create it, else return an existing connection
  if (db === null) {

    var def = Q.defer();

    // Initialize connection once
    MongoClient.connect(constants.mongoUrl, function (err, database) {
      if (err) {
        def.reject(err);
        throw err;
      }

      console.log('inside connection');
      db = database;
      def.resolve();
    });

    def.promise.then(function () {
      console.log('before returning connection');
      return db;
    });
  } else {
    console.log('connection already exists. returning');
    return db;
  }
}

module.exports.getDb = getDb;

这是我的文件,我正在调用mongoFactory

var mongoFactory = require('../../lib/mongoFactory');

module.exports = function() {

  return {

    find: function find(callback) {

      var db = mongoFactory.getDb();
      var cases = db.collection('mycollection'); // <-- First time i load the page, errors b/c db is undefined. Every other time after that it works just fine. ERROR: TypeError: Uncaught error: Cannot call method 'collection' of undefined
...

3 个答案:

答案 0 :(得分:2)

您的mongoFactory.getDb应该返回一个承诺,该承诺将在建立连接后完成(第一次将需要一段时间,之后将立即发生)。

/**
 * Creates and manages the Mongo connection pool
 *
 * @type {exports}
 */
var constants = require('../js/constants.js');
var Q = require('q');
var MongoClient = require('mongodb').MongoClient;
var db = null;

var getDb = function() {

  var def = Q.defer();

  console.log('db = '+db);
  // If the connection pool has not been created or has been closed, create it, else return an existing connection
  if (db === null) {

    // Initialize connection once
    MongoClient.connect(constants.mongoUrl, function (err, database) {
      if (err) {
        def.reject(err);
      }

      console.log('inside connection');
      db = database;
      def.resolve(db);
    });
  } else {
    def.resolve(db);
  }

  return def.promise;
}

module.exports.getDb = getDb;

并使用:

var mongoFactory = require( './mongoFactory' );
var con = mongoFactory.getDb();

con.done( function(db) {
    // use db here
} );

con.fail( function(err) {
   // error occurred
} );

您可能需要签出mongoskin这是一个围绕node-mongodb-native的承诺包装。

答案 1 :(得分:1)

在函数内部构造延迟不会自动阻止它 - 实际上它不能,promises are still asynchronous

undefined的情况下,您的函数确实没有返回任何内容(即db === null),并且只有在先前调用已经建立的情况下才返回数据库连接。相反,它应始终返回 Promise 代表(可能是以后到达的)最终连接。

/**
 * Creates and manages the Mongo connection pool
 *
 * @type {exports}
 */
var constants = require('../js/constants.js');
var Q = require('q');
var MongoClient = require('mongodb').MongoClient;
var dbPromise = null;

module.exports.getDb = function getDb() {
  // If the connection pool has been created or is being created, return the existing promise for that, else create it and return the promise for that
  if (dbPromise === null) {
    var def = Q.defer();

    // Initialize connection once
    MongoClient.connect(constants.mongoUrl, function (err, database) {
      if (err)
        def.reject(err);
      else
        def.resolve(database); // let the database be the result value of the promise!
    });
    return dbPromise = def.promise;
  } else {
    return dbPromise;
  }
};

既然你的函数返回了一个promise,你需要在then回调中使用它:

find: function find(callback) {
  return mongoFactory.getDb().then(function(db) {
    // db is always available in the promise callback
    var cases = db.collection('mycollection');
    // return a promise or a value from the callback
  }); // and find will return a promise for that value
}

答案 2 :(得分:0)

MongoClient.connect本质上是异步的,为什么不以nodejs的方式呢?我会更改您的getDb签名以接受回调:

var getDb = function(callback) {
  console.log('db = '+db);
  // If the connection pool has not been created or has been closed, create it, else return an existing connection
  if (db === null) {

    // Initialize connection once
    MongoClient.connect(constants.mongoUrl, function (err, database) {
      if (err) {
        callback(err);
        return;
      }

      console.log('inside connection');
      db = database;
      callback(null, db);
    });
  } else {
    console.log('connection already exists. returning');
    callback(null, db);
  }
}

然后你的消费者必须:

mongoFactory.getDb(function(err, db) {
  if (err) {
     // handle error
  }
  var cases = db.collection('mycollection');
});