require在node.js中的行为
我目前有一个数据库连接模块包含以下内容:
var mongodb = require("mongodb"); var client = mongodb.MongoClient; client.connect('mongodb://host:port/dbname', { auto_reconnect: true }, function(err, db) { if (err) { console.log(err); } else { // export db as member of exports module.exports.db = db; } } );
然后我可以成功访问它,执行以下操作:
users.js
var dbConnection = require("./db.js"); var users = dbConnection.db.collection("users"); users.find({name: 'Aaron'}).toArray(function(err, result) { // do something });
但是,如果我改为导出module.exports = db
,即尝试将exports
对象分配给db
对象,而不是使其成为exports的成员,并尝试通过var db = require("./db.js");
在users.js
访问它var db = require("./db.js");
对象是不确定的,为什么?
如果是因为连接build立有延迟(不require()
等到模块在分配module.exports的值之前运行它的代码),那么为什么这两个例子都不起作用呢?
one.js
setTimeout(function() { module.exports.x = {test: 'value'}; }, 500);
two.js
var x = require("./one"); console.log(x.test);
要么
one.js
setTimeout(function() { module.exports.x = {test: 'value'}; }, 500);
two.js
setTimeout(function() { var x = require("./one"); console.log(x.test); }, 1000);
运行$ node two.js
在两种情况下打印undefined
,而不是value
。
这里有三个关键要点,然后我会详细解释。
- module.exports是一个对象,对象通过JavaScript中的引用副本传递。
- require是一个同步函数。
- client.connect是一个asynchronous函数。
如你所说,这是一个时机的事情。 node.js不能知道module.exports将在以后更改。 这不是问题。 它怎么会知道?
当require
运行时,它会根据您input的pathfind满足其要求的文件,读取并执行它,并cachingmodule.exports,以便其他模块可以require
相同的模块,而不必重新初始化它弄乱variables范围等)
client.connect是一个asynchronous的函数调用,所以执行后,模块完成执行, require
调用存储module.exports引用的一个副本,并将其返回给users.js。 然后你设置module.exports = db
,但是为时已晚。 您正在使用对db的引用replacemodule.exports引用,但节点中的模块导出require
caching指向旧对象。
最好将module.exports定义为一个函数,它将获得一个连接,然后将其传递给一个callback函数,如下所示:
var mongodb = require("mongodb"); var client = mongodb.MongoClient; module.exports = function (callback) { client.connect('mongodb://host:port/dbname', { auto_reconnect: true }, function(err, db) { if (err) { console.log(err); callback(err); } else { // export db as member of exports callback(err, db); } } ) };
警告:虽然这不在本答案的范围之内,但要非常小心以上代码,以确保正确closures/返回连接,否则将泄漏连接。
是的, dbConnection.db
是未定义的,因为连接是asynchronous进行的,这意味着节点代码只是继续执行而不需要等待build立数据库连接。
在分配module.exports的值之前,不应该要求()等到模块完成运行其代码?
不,它只是不这样工作。 require
是代码总是在那里。 数据库连接不是代码,并不总是在那里。 最好不要混淆这两种types的资源,以及如何从您的程序中引用它们。
在分配module.exports的值之前,不应该'require()等到模块完成运行它的代码之前?
module.exports.db
在callback中设置,这个操作是asynchronous的,所以在user.js
你不能得到db.collection
。 在connect
callback中添加集合会更好。
您可以使用此答案更改您的代码并在其他模块中使用shared connection
。
问题是什么? 这就是require
工作的方式 – 它将模块同步到您的输出。
您build议“等到代码运行”可以回答两个方面:
- 它等待代码运行。
setTimeout
已成功完成。 学习从实际线程中分离未来的asynchronouscallback。 - 如果你的意思是“直到所有的asynchronouscallback运行”,这是胡说八道 – 如果其中一些根本不运行,因为它等待,我不知道,鼠标点击,但用户没有附加鼠标呢? (甚至你怎么定义'所有的代码已经运行?'每个语句至less运行一次?怎么样
if (true) { thisruns(); } else { thiswontrunever(); }
?)
- MissingSchemaError:架构没有被注册为模型,mongoose.model在架构之前调用
- res.json返回无意修改的input
- 如何在node + express中重新运行请求处理程序?
- AngularJS,ng-view + css3与jade模板的关键帧 – ng-cloak不起作用
- 从express.js中删除所有标题
- Node.js,PostgreSQL错误:主机没有pg_hba.conf条目
- 当express.static(__ dirname)函数在node.js中使用express时,redirect到错误的html页面
- 在Node.jsunit testing中重置MySQL自动增量作为拆卸步骤
- ExpressJS – 具有路由分离的Socket.IO