您好,登錄后才能下訂單哦!
這篇文章主要介紹“Node的模塊機制是什么”,在日常操作中,相信很多人在Node的模塊機制是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Node的模塊機制是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
在CommonJs規范提出之前,Javascript是沒有模塊系統的,這意味著我們很難開發大型的應用,因為代碼的組織會比較困難。
首先CommonJS不是Node獨有的東西,CommonJs是一種模塊規范,定義了如何引用和導出模塊,Nodejs只是實現了這個規范,CommonJS模塊規范主要分為模塊引用、模塊定義和模塊標識三個部分。
模塊引用
模塊引用就是我們可以通過require
引入其它的模塊。
const { add } = require('./add'); const result = add(1 ,2);
模塊定義
一個文件就是一個模塊,模塊里會提供兩個變量,分別為module和exports。module為當前模塊本身,exports為要導出的內容,同時exports為module的一個屬性,即exports為module.exports。其他模塊通過require導入的內容即為module.exports的內容。
// add.js exports.add = (a, b) => { return a + b; }
模塊標識
模塊標識即為require里面的內容,比如require('./add')
,則模塊標識為./add
。
通過CommonJS構建的這套模塊導入導出機制使得用戶完全無需考慮變量污染,可以方便的構建大型應用。
Node的模塊實現
Node實現了CommonJs規范,并且增加了一些自己需要的特性。Node為了實現CommonJs規范主要做了以下三件事情:
路徑分析
文件定位
編譯執行
路徑分析
當執行require()的時候,require接收的參數即為模塊標識符,node通過模塊標識符來進行路徑分析。路徑分析的目的就是為了通過模塊標識符找到這個模塊所在的路徑。首先,node的模塊分為兩類,分別是核心模塊和文件模塊。核心模塊是node自帶的模塊,文件模塊是用戶編寫的模塊。同時文件模塊又分為相對路徑形式的文件模塊、絕對路徑形式的文件模塊和非路徑形式的文件模塊(比如express)。
當node找到一個文件模塊之后,會將這個模塊編譯執行并且緩存起來,大致原理是將這個模塊的完整路徑作為key,編譯后的內容作為值,后續再第二次引入這個模塊的時候就不需要再進行路徑分析文件定位編譯執行這幾個步驟了,可以直接從緩存中讀取編譯好的內容。
// 緩存的模塊示意: const cachedModule = { '/Usr/file/src/add.js': 'add.js編譯后的內容', 'http': 'Node自帶的http模塊編譯后的內容', 'express': '非路徑形式自定義文件模塊express編譯后的內容' // ... }
當要查找require導入的模塊時,查找模塊的順序是先查看緩存里是否已經有該模塊,如果緩存里面沒有再查看核心模塊,然后再查找文件模塊。其中路徑形式的文件模塊比較好查找,根據相對或絕對路徑就可以得到完整的文件路徑。非路徑形式的自定義文件模塊查找起來會相對麻煩一些,Node會從node_modules這個文件夾里去查找是否有這個文件。
node_modules這個目錄在哪里呢,比如說我們當前執行的文件為/Usr/file/index.js;
/** * /Usr/file/index.js; */ const { add } = require('add'); const result = add(1, 2);
這個模塊里我們有引入了一個add模塊,這個add不是一個核心模塊也不是一個路徑形式的文件模塊,那么這時候如何找到這個add模塊呢。
module有一個paths的屬性,查找add模塊的路徑在paths這個屬性里,我們可以把這個屬性打出來看一下:
/** * /Usr/file/index.js; */ console.log(module.paths);
我們在file目錄下執行node index.js可以打印出paths的值。paths里的值是一個數組,如下:
[ '/Usr/file/node_modules', '/Usr/node_modules', '/node_modules', ]
即Node會依次從上面的目錄里尋在是否包含add這個模塊,原理和原型鏈類似。先從當前執行的文件的同級目錄的node_modules文件夾里開始找,如果沒找到或者沒有node_modules這個目錄,則繼續往上級查找。
文件定位
路徑分析和文件定位是搭配一起使用的,文件標識符可以是不帶后綴的,也可能通過路徑分析找到的是一個目錄或者一個包,這個時候要定位到具體的文件需要一些額外的處理。
文件擴展名分析
const { add } = require('./add');
比如上面這段代碼,文件標識符是不帶擴展名的,這個時候node會依次查找是否存在.js、.json、.node文件。
目錄和包分析
同樣是上面這段代碼,通過./add
查找到的可能不是一個文件,可能是一個目錄或者包(通過判斷add文件夾下是否有package.json文件來判斷是目錄還是包)。這個時候文件定位的步驟是這樣的:
查看是否有package.json文件
尋找目錄下的index作為文件(依次查找index.js、index.json、index.node)
讀取package.json里的main字段的值作為文件
有
沒有
如果package.json里沒有main字段,那么也會將index作為文件,然后進行擴展名分析找到對應后綴的文件。
模塊編譯
我們開發中主要遇到的模塊為json模塊和js模塊。
json模塊編譯
當我們require一個json模塊的時候,實際上Node會幫我們使用fs.readFilcSync去讀取對應的json文件,得到json字符串,然后調用JSON.parse解析得到json對象,再賦值給module.exports,然后給到require。
js模塊編譯
當我們require一個js模塊的時候,比如
// index.js const { add } = require('./add');
// add.js exports.add = (a, b) => { return a + b; }
這個時候發生了什么呢,為什么我們可以直接在模塊里使用module、exports、require這些變量。這是因為Node在編譯js模塊的時候對模塊的內容進行了首尾的包裝。
比如add.js這個模塊,實際編譯的時候是會被包裝成類似這樣的結構:
(function(require, exports, module) { exports.add = (a, b) => { return a + b; } return module.exports; })(require, module.exports, module)
即我們編寫的js文件是會被包裝成一個函數,我們編寫的只是這個函數里的內容,Node后續的包裝的過程對我們隱藏了。這個函數支持傳入一些參數,其中就包括require、exports和module。
當編譯完js文件后,就會執行這個文件,node會將對應的參數傳給這個函數然后執行,并且返回module.exports值給到require函數。
到此,關于“Node的模塊機制是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。