首頁 > web前端 > js教程 > 主體

Node.js中require的工作原理淺析_node.js

WBOY
發布: 2016-05-16 16:43:12
原創
1396 人瀏覽過

幾乎所有的Node.js開發人員可以告訴你`require()`函數做什麼,但我們又有多少人真正知道它是如何運作的?我們每天都使用它來載入函式庫和模組,但它的行為,對我們來說反而是一個謎。

出於好奇,我鑽研了node的核心程式碼來找出引擎下發生了什麼事。但這並不是一個單一的功能,我在node的模組系統的找到了module.js。該文件包含一個令人驚訝的強大的且相對陌生的核心模組,控制每個文件的加載,編譯和快取。 `require()`,它的橫空出世,只是冰山的一角。

module.js

複製程式碼 程式碼如下:

function Module(id, parent) {
  this.id = id;
  this.exports = {};
  this.parent = parent;
  // ...

在module.js在Node.js內部主要承擔兩個角色。首先,它為所有的Node.js模組提供了一個基礎。每個檔案是基本模組new出的一個新實例,即使在該檔案已經運行之後,仍然存在。這就是為什麼我們能夠性為module.exports附加屬並在需要時返回它們。

此模組的第二大任務是處理node的模組載入機制。我們使用的獨立運算的「require」函數其實是抽象概念的module.require,這本身就是只是一個簡單的關於Module._load功能的封裝。此load方法處理每個檔案的實際加載,並在那裡開始我們的旅程。

Module._load

複製程式碼 程式碼如下:

Module._load = function(request, parent, isMain) {
  // 1. Check Module._cache for the cached module.
  // 2. Create a new Module instance if cache is empty.
  // 3. Save it to the cache.
  // 4. Call module.load() with your the given filename.
  //    This will call module.compile() after reading the file contents.
  // 5. If there was an error loading/parsing the file,
  //    delete the bad module from the cache
  // 6. return module.exports
};

Module._load負責載入新的模組和管理模組的快取。快取載入的每個模組減少冗餘檔案的讀取次數,並可以顯著地加快您應用程式的速度。此外,共享模組實例允許單例特性的模組,保持在專案中的狀態。

如果某個模組沒有在快取中存在,Module._load將建立該檔案的一個新的基本模組。然後,它會告訴模組在將它們發送到module._compile之前閱讀新檔案的內容。 [1]

如果您注意到上面的步驟#6,你會看到module.exports已被回傳給使用者。這就是為什麼當你在定義公共介面使用時,你使用exports和module.exports,因為Module._load將接下來傳回require的內容。我很驚訝,這裡沒有更多的功能,但如果有的話那更好。

module._compile

複製程式碼 程式碼如下:

Module.prototype._compile = function(content, filename) {
  // 1. Create the standalone require function that calls module.require.
  // 2. Attach other helper methods to require.
  // 3. Wraps the JS code in a function that provides our require,
  //    module, etc. variables locally to the module scope.
  // 4. Run that function
};

· 這是真正的奇蹟發生的地方。首先,一個特殊的獨立操作的require函數是為該模組創建的。這是我們需要的並且都熟悉的功能。而函數本身只是一個在Module.require的封裝,它也包含了一些便於我們使用的鮮為人知的輔助方法:

· require():載入一個外部模組
· require.resolve():解析一個模組名稱到它的絕對路徑
· require.main:主模組
· require.cache:所有快取好的模組
· ·require.extensions:根據其副檔名,對於每個有效的檔案類型可使用的編制方法

一旦require準備好了,整個載入的原始碼就會被封裝在一個新的函數裡,可以接受require,module,exports和所有其他暴露的變數作為參數。這是一個僅為封裝模組的而創建的函數,以便於在防止與Node.js的環境產生衝突。

複製程式碼 程式碼如下:

(function (exports, require, module, __filename, __dirname) {
  // YOUR CODE INJECTED HERE!
});

這個Module._compile方法是同步執行的,所以對Module._load的呼叫只能等到這段程式碼運行結束,並將module.exprts傳回給使用者。

結論

因此,我們已經了解了require的全部程式碼,並且已經初步了解它是如何運作的。

如果你已經按照這一切的方式做了,那麼你已經為最後的秘密做好準備:require('module')。這是正確的,該模組系統本身可以透過模組系統被載入。盜夢空間。這可能聽起來很奇怪,但它可以讓使用者空間同模組載入系統互動起來,並不需要鑽研Node.js核心。受歡迎的模組都像這樣被建立。 [2]

如果您想了解更多,請自行查看module.js原始碼。還有很多東西足夠你頭痛一段時間了。第一個可以告訴我什麼是NODE_MODULE_CONTEXTS「以及為什麼它被加入的人可以得到加分獎勵 :)

[1] module._compile方法只用於執行JavaScript檔案。 JSON檔案需經JSON.parse() 解析並回傳

[2]然而,這兩個模組都建立在私有模組的方法,如Module._resolveLookupPaths和Module._findPath。你可以認為這並沒有好多了...

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板