Model view controller 可以在node.js模块中异步初始化导出吗?
由于Node.js上的MongoDB数据库访问和初始化是异步的,所以我想为每个集合定义一个模块,在db初始化之后导出包装的db调用 这样的“Cars.model.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); }; });
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测试了这一点,它是有效的