簡體   English   中英

node.js中require的行為

[英]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個關鍵點需要理解,然后我將詳細解釋它們。

  1. module.exports是一個對象,並且對象通過JavaScript中的引用復制傳遞。
  2. require是一個同步功能。
  3. client.connect是一個異步函數。

正如您所建議的,這是時機。 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);
             }
          }
    )
};

警告:盡管超出了此答案的范圍,但是請對上述代碼非常小心,以確保正確關閉/返回連接,否則將泄漏連接。

`require()不應該等到模塊完成其代碼運行后才分配module.exports的值嗎?

module.exports.db是在回調中設置的,此操作是異步的,因此在user.js中無法獲取db.collection 最好在connect回調中添加集合。

您可以使用答案來更改代碼,並在其他模塊中使用shared connection

是的, dbConnection.db是未定義的,因為該連接是異步進行的,這意味着按照定義,節點代碼將繼續執行而無需等待建立數據庫連接。

是否不應該require()等到模塊完成其代碼運行,然后再分配module.exports的值?

不,那不是那樣的。 require是用於始終存在的代碼。 數據庫連接不是代碼,也不總是存在。 最好不要混淆這兩種類型的資源以及如何從程序中引用它們。

那是什么問題呢? 這就是require工作方式-它同步獲取模塊並將輸出傳遞給您。

您建議“等待代碼運行”的方法有兩種:

  1. 它等待直到代碼運行。 setTimeout已成功完成。 學習將面向未來的異步回調與實際線程分開。
  2. 如果您的意思是“直到所有異步回調都運行完畢”,那是胡說八道-如果根本不運行其中的某些,因為它等待(我不知道)鼠標單擊,但是用戶沒有鼠標連接? (以及如何定義“所有代碼都已運行?”每個語句至少運行了一次? if (true) { thisruns(); } else { thiswontrunever(); }呢?)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM