一、簡介
Node.js採用CommonJS規範來組織模塊,即在每個文件中定義模塊,通過exports對象或module.exports對象對外暴露介面,通過require函數來引用其他模塊。
在Node.js內部,處理模塊載入的主要邏輯被封裝在模塊內部模塊cjs的loader.js文件中。該文件的作用是確定模塊的文件路徑和文件名,以及使用該路徑來讀取文件內容並在代碼中執行該模塊。因此,深入了解internal/modules/cjs/loader.js文件對於了解Node.js模塊載入機制非常重要。
二、分析內部模塊cjs的loader.js文件
loader.js文件將Node.js的模塊載入機制進行了抽象,可以分為以下幾個步驟:
1. 從module對象中獲取模塊信息
function tryModuleLoad(module, filename) {
var threw = true;
try {
module.load(filename);
threw = false;
} finally {
if (threw) {
delete Module._cache[filename];
}
}
}
該函數的作用是嘗試載入模塊。
首先從Module._cache對象中獲取模塊,如果緩存中存在模塊,則跳過載入步驟,直接返回該模塊。
如果緩存中不存在模塊,則根據文件名解析出完整文件路徑,並捕獲可能的異常。
如果異常被捕獲,將刪除緩存中的模塊信息。
如果沒有異常,將調用模塊對象的load方法實現模塊載入和執行。
2. 獲取模塊對應的文件路徑
function resolveFilename(request, parentModule, isMain) {
var resolvedModule = Module._resolveFilename(request, parentModule, isMain);
return resolvedModule;
}
該函數的作用是獲取一個請求模塊路徑的完整路徑名。
該方法內部調用了Module._resolveFilename方法,通過路徑分析演算法找到對應的文件,查找路徑順序為:
- 原始文件路徑
- 系統模塊
- node_modules文件夾
3. 載入模塊
Module.prototype.load = function(filename) {
var extension = pathModule.extname(filename) || '.js';
if (!Module._extensions[extension]) extension = '.js';
Module._extensions[extension](this, filename);
this.loaded = true;
};
該方法的作用是載入模塊。
首先通過node的pathModule模塊獲取文件擴展名,再根據擴展名查找對應的Module._extensions對象中的方法,如果找到對應的方法,則執行該方法載入模塊。
例如,若文件擴展名為.js,則調用Module._extensions[‘.js’]。
4. 編譯模塊
Module._extensions['.js'] = function(module, filename) {
var content = fs.readFileSync(filename, 'utf8');
module._compile(stripBOM(content), filename);
}
該函數的作用是讀取文件,並將讀取到的內容作為字元串編譯成可執行的代碼。
代碼讀取使用了Node.js的文件系統模塊(fs模塊)中的readFileSync()方法。
讀取出來的內容會有BOM標記,所以需要stripBOM()函數將其去除,該函數被定義在Module.js文件中。
最後,執行module._compile()函數將字元串轉換成可執行的代碼並存儲在module.exports對象中。
三、總結
Node.js的內部模塊cjs的loader.js文件是Node.js的模塊載入機制的核心部分,它負責解析模塊的文件路徑和讀取文件內容,並將內容編譯成可執行的代碼。對Node.js的模塊載入機制進行深入的了解,有助於開發者更好地理解Node.js的模塊化開發,進而開發出更好的應用程序。
原創文章,作者:DXRMK,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/362037.html