[英]Behavior of require in 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
對象,而不是使其成為出口的一員,並嘗試訪問它users.js
通過var db = require("./db.js");
對象未定義,為什么?
如果是因為建立連接存在延遲(不require()
等到模塊完成運行其代碼之后再分配module.exports的值?),那么為什么這些示例都不起作用?
一個.js
setTimeout(function() {
module.exports.x = {test: 'value'};
}, 500);
two.js
var x = require("./one");
console.log(x.test);
要么
一個.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
。
這里有3個關鍵點需要理解,然后我將詳細解釋它們。
正如您所建議的,這是時機。 node.js不知道module.exports將在以后更改。 那不是問題。 它怎么知道的?
當require
運行時,它將根據您輸入的路徑找到一個滿足其要求的文件,然后讀取並執行該文件,並緩存module.exports,以便其他模塊可以require
相同的模塊,而不必重新初始化它(弄亂變量作用域等)
client.connect是異步函數調用,因此在執行它之后,模塊完成執行,而require
調用存儲module.exports參考的副本並將其返回給users.js。 然后設置module.exports = db
,但是為時已晚。 您正在用對db的引用替換module.exports引用,但是節點中的模塊導出require
高速緩存指向舊對象。
最好將module.exports定義為將獲得連接的函數,然后將其傳遞給回調函數,如下所示:
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);
}
}
)
};
警告:盡管超出了此答案的范圍,但是請對上述代碼非常小心,以確保正確關閉/返回連接,否則將泄漏連接。
是的, dbConnection.db
是未定義的,因為該連接是異步進行的,這意味着按照定義,節點代碼將繼續執行而無需等待建立數據庫連接。
是否不應該require()等到模塊完成其代碼運行,然后再分配module.exports的值?
不,那不是那樣的。 require
是用於始終存在的代碼。 數據庫連接不是代碼,也不總是存在。 最好不要混淆這兩種類型的資源以及如何從程序中引用它們。
那是什么問題呢? 這就是require
工作方式-它同步獲取模塊並將輸出傳遞給您。
您建議“等待代碼運行”的方法有兩種:
setTimeout
已成功完成。 學習將面向未來的異步回調與實際線程分開。 if (true) { thisruns(); } else { thiswontrunever(); }
呢?)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.