相關推薦:《》
大多數人都知道Node.js中require()函數做什麼的,但是有多少人知道它的工作原理呢?我們每天使用它載入庫包和模組,但是它的內部行為原理很神祕。
我們追尋Node模組系統的核心: module.js,這個檔案包含一個令人驚訝的神奇功能,它負責載入 編譯和快取每個用過的檔案,讓我們揭開它的神祕面紗。
function Module(id, parent) { this.id = id; this.exports = {}; this.parent = parent; // ...
在module.js中可以發現這個Module型別,扮演兩個主要角色:首先,它提供一個所有Node.js模組從其檔案被載入時構建一個範例的基礎功能,甚至在檔案執行時持久,這就是為什麼我們能夠將一些屬性加入module.exports,並在需要時返回它們。
module的第二個事情是處理Node模組的載入機制,標準的require函數其實是基於module.require的抽象,後者只是一個對Module._load的簡單包裝,載入方法處理每個檔案的實際載入。看看它的程式碼大概如下:
Module._load = function(request, parent, isMain) { // 1.在Module._cache中檢查模組是否被快取 // 2.如果快取中為空,建立一個新的模組範例。 // 3. 儲存到快取 // 4. 使用指定的名稱呼叫module.load() // 在讀取了檔案內容後將呼叫module.compile() // 5.如果載入和分析檔案時有錯誤 // 從快取中刪除壞的模組 // 6. 返回 module.exports };
Module._load負責載入新的模組並且管理模組快取,快取每個模組能夠降低檔案的讀取頻率,從而提高效能,共用模組範例允許像單例模組那樣跨應用儲存狀態。
如果一個模組在快取中不存在,Module._load將讀取檔案建立一個新的,讀取檔案內容成功後會呼叫module._compile
如果你注意上面第六步,你會看到返回的是module.exports,這就是為什麼當你定義公共介面時,可以使用exports和module.exports,因為它們確實是Model._load和require返回的。
下面看看module._compile:
Module.prototype._compile = function(content, filename) { // 1. 建立呼叫模組需要的require標準函數 // 2.將其他幫助方法加入require. // 3.包裝JS程式碼到一個函數,這個函數提供我們的require // 模組, 比如變數在地化到模組的作用域 // 4.返回這個函數 };
這裡有魔術發生,首先,一個特殊的標準require函數將被建立,這就是我們熟悉的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.exports給使用者。
現在,我們已經知道require('模組')是如何通過模組系統載入你定義的模組的, module.js source code包含更多程式碼原理,如果你有興趣可以發現更多。
更多程式設計相關知識,請存取:!!
以上就是Node.js中require()是如何工作的?工作原理介紹的詳細內容,更多請關注TW511.COM其它相關文章!