Model view controller 可以在node.js模块中异步初始化导出吗?

Model view controller 可以在node.js模块中异步初始化导出吗?,model-view-controller,design-patterns,mongodb,asynchronous,node.js,Model View Controller,Design Patterns,Mongodb,Asynchronous,Node.js,由于Node.js上的MongoDB数据库访问和初始化是异步的,所以我想为每个集合定义一个模块,在db初始化之后导出包装的db调用 这样的“Cars.model.js”模块如下所示: var db = require("mongodb"); db.collection("cars", function(err, col) { exports.getCars = function(callback) { col.find({}, callback); }; });

由于Node.js上的MongoDB数据库访问和初始化是异步的,所以我想为每个集合定义一个模块,在db初始化之后导出包装的db调用

这样的“Cars.model.js”模块如下所示:

var db = require("mongodb");
db.collection("cars", function(err, col) {
    exports.getCars = function(callback) {
        col.find({}, callback);
    };
});
var col = require("main").collectionCache; // populated
exports.getCars = function(callback) {
    col["cars"].find({}, callback);
};
var carModel = require("Cars.model.js").getCars;
getCars.then(cars) {
    // (do something with cars here...)
};
以便其他模块可以运行:

var carModel = require("Cars.model.js").getCars;
getCars(err, cars) {
    // (do something with cars here...)
};
碰巧我的
getCars
没有定义,因为在运行第二个模块时db访问还没有初始化


如何创建这样的异步数据库模型?

离开文件后,无法写入
导出文件。你一定是挡住了。为了避免阻塞,我将使用延迟加载资源

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
类/对象,使代码更整洁/更枯燥。

我相信这个简单的解决方案是有效的:将对
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 db = require("mongodb");
db.collection("cars", function(err, col) {
    exports.getCars = function(callback) {
        col.find({}, callback);
    };
});
var col = require("main").collectionCache; // populated
exports.getCars = function(callback) {
    col["cars"].find({}, callback);
};
var carModel = require("Cars.model.js").getCars;
getCars.then(cars) {
    // (do something with cars here...)
};

此解决方案将异步问题从模型转移到根数据库模型,使模型更易于开发。

我是新手,所以不要生我的气

我用承诺来做到这一点:

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 db = require("mongodb");
db.collection("cars", function(err, col) {
    exports.getCars = function(callback) {
        col.find({}, callback);
    };
});
var col = require("main").collectionCache; // populated
exports.getCars = function(callback) {
    col["cars"].find({}, callback);
};
var carModel = require("Cars.model.js").getCars;
getCars.then(cars) {
    // (do something with cars here...)
};

这是个坏主意,请让我知道,因为这是我现在正在做的。

@adrienjoly不太干燥,也不太容易伸展!我相信,通过在运行任何逻辑(以及模型)之前填充集合缓存,可以将大部分异步复杂性转移到应用程序init模块。只要stackoverflow允许我回答自己的问题,我就会提出一些代码(现在5小时内);-)@adrienjoly我建议在init中进行againts阻塞,直到它被加载。最好让它在后台加载,并在加载时将数据请求添加到缓冲区。我先这样做了,但我的应用程序模块无法编译,直到异步db加载程序触发收集回调,由于回调中定义了模型的导出…您可以异步写入module.exports。实际上,这还增加了服务器启动时间,因为您必须等待加载所有集合。我也怀疑这是否有效,因为您对
的编写是异步导出的,我不知道导出是通过引用还是通过值复制的。事实上,它确实增加了服务器启动时间,但简化了模型的开发,并优化同时打开的集合的数量。关于导出.collectionCache
的异步填充,我认为这是正确的,因为javascript对象始终作为引用保留。但是,如果我异步重新定义此导出,它将不起作用。我仍然认为您的逻辑是反向的。Models.js不应要求
main
。您只需要考虑异步而不是同步。对我来说,最重要的是代码工作正常,可读性强,易于维护。我不介意黑客^^我已经用Node6.9和Node7.2测试了这一点,它是有效的