站長(zhǎng)資訊網(wǎng)
        最全最豐富的資訊網(wǎng)站

        深入了解Node的模塊機(jī)制,聊聊模塊實(shí)現(xiàn)流程

        本篇文章帶大家了解一下CommonJs規(guī)范和Node的模塊機(jī)制,介紹一下Node實(shí)現(xiàn)CommonJs規(guī)范的基本流程,希望對(duì)大家有所幫助!

        深入了解Node的模塊機(jī)制,聊聊模塊實(shí)現(xiàn)流程

        在CommonJs規(guī)范提出之前,Javascript是沒(méi)有模塊系統(tǒng)的,這意味著我們很難開(kāi)發(fā)大型的應(yīng)用,因?yàn)榇a的組織會(huì)比較困難。

        什么是CommonJs規(guī)范


        首先CommonJS不是Node獨(dú)有的東西,CommonJs是一種模塊規(guī)范,定義了如何引用和導(dǎo)出模塊,Nodejs只是實(shí)現(xiàn)了這個(gè)規(guī)范,CommonJS模塊規(guī)范主要分為模塊引用、模塊定義和模塊標(biāo)識(shí)三個(gè)部分。

        模塊引用

        模塊引用就是我們可以通過(guò)require引入其它的模塊。

        const { add } = require('./add'); const result = add(1 ,2);

        模塊定義

        一個(gè)文件就是一個(gè)模塊,模塊里會(huì)提供兩個(gè)變量,分別為module和exports。module為當(dāng)前模塊本身,exports為要導(dǎo)出的內(nèi)容,同時(shí)exports為module的一個(gè)屬性,即exports為module.exports。其他模塊通過(guò)require導(dǎo)入的內(nèi)容即為module.exports的內(nèi)容。

        // add.js exports.add = (a, b) => {     return a + b; }

        模塊標(biāo)識(shí)

        模塊標(biāo)識(shí)即為require里面的內(nèi)容,比如require('./add'),則模塊標(biāo)識(shí)為./add

        通過(guò)CommonJS構(gòu)建的這套模塊導(dǎo)入導(dǎo)出機(jī)制使得用戶完全無(wú)需考慮變量污染,可以方便的構(gòu)建大型應(yīng)用。

        Node的模塊實(shí)現(xiàn)


        Node實(shí)現(xiàn)了CommonJs規(guī)范,并且增加了一些自己需要的特性。Node為了實(shí)現(xiàn)CommonJs規(guī)范主要做了以下三件事情:

        • 路徑分析

        • 文件定位

        • 編譯執(zhí)行

        路徑分析

        當(dāng)執(zhí)行require()的時(shí)候,require接收的參數(shù)即為模塊標(biāo)識(shí)符,node通過(guò)模塊標(biāo)識(shí)符來(lái)進(jìn)行路徑分析。路徑分析的目的就是為了通過(guò)模塊標(biāo)識(shí)符找到這個(gè)模塊所在的路徑。首先,node的模塊分為兩類,分別是核心模塊和文件模塊。核心模塊是node自帶的模塊,文件模塊是用戶編寫的模塊。同時(shí)文件模塊又分為相對(duì)路徑形式的文件模塊、絕對(duì)路徑形式的文件模塊和非路徑形式的文件模塊(比如express)。

        深入了解Node的模塊機(jī)制,聊聊模塊實(shí)現(xiàn)流程

        當(dāng)node找到一個(gè)文件模塊之后,會(huì)將這個(gè)模塊編譯執(zhí)行并且緩存起來(lái),大致原理是將這個(gè)模塊的完整路徑作為key,編譯后的內(nèi)容作為值,后續(xù)再第二次引入這個(gè)模塊的時(shí)候就不需要再進(jìn)行路徑分析文件定位編譯執(zhí)行這幾個(gè)步驟了,可以直接從緩存中讀取編譯好的內(nèi)容。

        // 緩存的模塊示意: const cachedModule = {     '/Usr/file/src/add.js': 'add.js編譯后的內(nèi)容',     'http': 'Node自帶的http模塊編譯后的內(nèi)容',     'express': '非路徑形式自定義文件模塊express編譯后的內(nèi)容'     // ... }

        當(dāng)要查找require導(dǎo)入的模塊時(shí),查找模塊的順序是先查看緩存里是否已經(jīng)有該模塊,如果緩存里面沒(méi)有再查看核心模塊,然后再查找文件模塊。其中路徑形式的文件模塊比較好查找,根據(jù)相對(duì)或絕對(duì)路徑就可以得到完整的文件路徑。非路徑形式的自定義文件模塊查找起來(lái)會(huì)相對(duì)麻煩一些,Node會(huì)從node_modules這個(gè)文件夾里去查找是否有這個(gè)文件。

        node_modules這個(gè)目錄在哪里呢,比如說(shuō)我們當(dāng)前執(zhí)行的文件為/Usr/file/index.js;

        /**  * /Usr/file/index.js; */  const { add } = require('add'); const result = add(1, 2);

        這個(gè)模塊里我們有引入了一個(gè)add模塊,這個(gè)add不是一個(gè)核心模塊也不是一個(gè)路徑形式的文件模塊,那么這時(shí)候如何找到這個(gè)add模塊呢。

        module有一個(gè)paths的屬性,查找add模塊的路徑在paths這個(gè)屬性里,我們可以把這個(gè)屬性打出來(lái)看一下:

        /**  * /Usr/file/index.js; */  console.log(module.paths);

        我們?cè)趂ile目錄下執(zhí)行node index.js可以打印出paths的值。paths里的值是一個(gè)數(shù)組,如下:

        [ '/Usr/file/node_modules', '/Usr/node_modules', '/node_modules', ]

        即Node會(huì)依次從上面的目錄里尋在是否包含add這個(gè)模塊,原理和原型鏈類似。先從當(dāng)前執(zhí)行的文件的同級(jí)目錄的node_modules文件夾里開(kāi)始找,如果沒(méi)找到或者沒(méi)有node_modules這個(gè)目錄,則繼續(xù)往上級(jí)查找。

        文件定位

        路徑分析和文件定位是搭配一起使用的,文件標(biāo)識(shí)符可以是不帶后綴的,也可能通過(guò)路徑分析找到的是一個(gè)目錄或者一個(gè)包,這個(gè)時(shí)候要定位到具體的文件需要一些額外的處理。

        文件擴(kuò)展名分析

        const { add } = require('./add');

        比如上面這段代碼,文件標(biāo)識(shí)符是不帶擴(kuò)展名的,這個(gè)時(shí)候node會(huì)依次查找是否存在.js、.json、.node文件。

        目錄和包分析

        同樣是上面這段代碼,通過(guò)./add查找到的可能不是一個(gè)文件,可能是一個(gè)目錄或者包(通過(guò)判斷add文件夾下是否有package.json文件來(lái)判斷是目錄還是包)。這個(gè)時(shí)候文件定位的步驟是這樣的:

        • 查看是否有package.json文件
            • 讀取package.json里的main字段的值作為文件
          • 沒(méi)有
            • 尋找目錄下的index作為文件(依次查找index.js、index.json、index.node)

        如果package.json里沒(méi)有main字段,那么也會(huì)將index作為文件,然后進(jìn)行擴(kuò)展名分析找到對(duì)應(yīng)后綴的文件。

        模塊編譯

        我們開(kāi)發(fā)中主要遇到的模塊為json模塊和js模塊。

        json模塊編譯

        當(dāng)我們r(jià)equire一個(gè)json模塊的時(shí)候,實(shí)際上Node會(huì)幫我們使用fs.readFilcSync去讀取對(duì)應(yīng)的json文件,得到j(luò)son字符串,然后調(diào)用JSON.parse解析得到j(luò)son對(duì)象,再賦值給module.exports,然后給到require。

        js模塊編譯

        當(dāng)我們r(jià)equire一個(gè)js模塊的時(shí)候,比如

        // index.js const { add } = require('./add');
        // add.js exports.add = (a, b) => {     return a + b; }

        這個(gè)時(shí)候發(fā)生了什么呢,為什么我們可以直接在模塊里使用module、exports、require這些變量。這是因?yàn)镹ode在編譯js模塊的時(shí)候?qū)δK的內(nèi)容進(jìn)行了首尾的包裝。

        比如add.js這個(gè)模塊,實(shí)際編譯的時(shí)候是會(huì)被包裝成類似這樣的結(jié)構(gòu):

        (function(require, exports, module) {   exports.add = (a, b) => {     return a + b;   }   return module.exports; })(require, module.exports, module)

        即我們編寫的js文件是會(huì)被包裝成一個(gè)函數(shù),我們編寫的只是這個(gè)函數(shù)里的內(nèi)容,Node后續(xù)的包裝的過(guò)程對(duì)我們隱藏了。這個(gè)函數(shù)支持傳入一些參數(shù),其中就包括require、exports和module。

        當(dāng)編譯完js文件后,就會(huì)執(zhí)行這個(gè)文件,node會(huì)將對(duì)應(yīng)的參數(shù)傳給這個(gè)函數(shù)然后執(zhí)行,并且返回module.exports值給到require函數(shù)。

        贊(0)
        分享到: 更多 (0)
        網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)
        主站蜘蛛池模板: 99精品视频在线观看婷| 国产欧美日韩精品专区| 99久久精品国产毛片| 亚洲av午夜福利精品一区| 国产亚洲精品高清在线| 国产高清在线精品二区一| 无码日韩精品一区二区三区免费 | 久久精品无码午夜福利理论片| 国产精品男男视频一区二区三区| 99RE6热在线精品视频观看| 亚洲精品高清在线| 欧美精品免费专区在线观看| 国产精品女人呻吟在线观看| 精品国产第1页| 97久久超碰国产精品2021| 久久丫精品国产亚洲av不卡| 亚洲欧美日韩国产精品一区二区| 国产欧美在线观看精品一区二区 | 亚洲精品成人网久久久久久| 久久99精品国产麻豆不卡| 99久久精品费精品国产 | 亚洲一区精品无码| 在线精品亚洲| 一级A毛片免费观看久久精品| 欧美 日韩 精品 另类视频| 精品国内自产拍在线观看 | 精品无码国产污污污免费网站| 尤物TV国产精品看片在线| 青春草无码精品视频在线观 | 久久久久久亚洲Av无码精品专口| 亚洲国产精品一区二区成人片国内| 无码AV动漫精品一区二区免费| 久久亚洲AV永久无码精品| 久久久久久无码国产精品中文字幕 | 国产精品一级香蕉一区| 18国产精品白浆在线观看免费| 91精品国产高清91久久久久久| 99久久精品费精品国产一区二区| 国产精品视频一区二区三区| 九九精品成人免费国产片| 国产精品91视频|