Можно ли инициализировать экспорт асинхронно в модуле node.js? - PullRequest
9 голосов
/ 21 июня 2011

Поскольку доступ к базе данных MongoDB и ее инициализация асинхронны в Node.js, я хотел бы определить один модуль для каждой коллекции, который экспортирует упакованные вызовы БД после инициализации БД.

Такой модуль "Cars.model.js" выглядит так:

var db = require("mongodb");
db.collection("cars", function(err, col) {
    exports.getCars = function(callback) {
        col.find({}, callback);
    };
});

, чтобы другие модули могли работать:

var carModel = require("Cars.model.js").getCars;
getCars(err, cars) {
    // (do something with cars here...)
};

Мне случилось, что getCars не был определен, потому что доступ к базе данных еще не был инициализирован во время запуска моего второго модуля.

Как вы справляетесь с созданием таких асинхронных моделей БД?

Ответы [ 3 ]

11 голосов
/ 21 июня 2011

Вы не можете писать в exports после того, как оставили файл.Вы должны быть блокирующим.Чтобы избежать блокировки, я бы использовал ленивую загрузку ресурсов.

var carCol;
var carEmitter = new require("events").EventEmitter;


exports.getCars = function(callback) {
  // if no car collection then bind to event
  if (carCol === undefined) {
    carEmitter.on("cars-ready", function() {
      callback(carCol);
    });
  } else {
    // we have cars, send them back
    callback(carCol);
  }
}

db.collection("cars", function(err, col) {
  // store cars
  carCol = col;
  // tell waiters that we have cars.
  carEmitter.emit("cars-ready");
});

Использование генераторов событий для эмуляции отложенной загрузки.Вы можете обобщить класс / объект LazyLoadedCollection, чтобы сделать код более аккуратным / более СУХИМ.

2 голосов
/ 17 июля 2014

Я новичок, поэтому не сердитесь на меня ...

Я использую обещания сделать это:

var db = require("mongodb"),
Q = require('q'),
getCarsDefer = Q.defer();

exports.getCars = getCarsDefer.promise;

db.collection("cars", function(err, col) {
  if(err){
    getCarsDefer.reject(err);
  }else{
     getCarsDefer.resolve(Q.ninvoke(col,'find'));
  };
});

Таким образом, вы можете получить свои машины так:

var carModel = require("Cars.model.js").getCars;
getCars.then(cars) {
    // (do something with cars here...)
};

Если это плохая идея, пожалуйста, дайте мне знать, потому что это то, чем я сейчас занимаюсь.

0 голосов
/ 22 июня 2011

Я считаю, что это простое решение работает: замените асинхронный вызов на getCars() синхронным вызовом кеша сбора, который будет заполнен до того, как будут вызваны модели.

Модуль запуска приложения main.js:

var db = require("mongodb");
exports.collectionCache = {};
db.collection("cars", function(err, col) {
    exports.collectionCache["cars"] = col;
    // ready => start application logic (incl. models) here
});  

Таким образом, «Cars.model.js» будет выглядеть так:

var col = require("main").collectionCache; // populated
exports.getCars = function(callback) {
    col["cars"].find({}, callback);
};

Это решение перемещает асинхронную проблему из моделей в модель корневой базы данных, упрощая разработку моделей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...