摘要:本篇將對規范,的文件模塊和核心模塊等做一個綜合的整理。其他后綴名的文件,都會被當成是文件進行處理。總結至此我們對的模塊整體的機制,大致已經整理清楚了,從模塊的導出,到引入,以及標識符的分析。
前言
模塊對于node來說是不可或缺的一部分,是服務端編程的基礎。趁著整理模塊之際,先將node部分的模塊的封裝等做一個總結。希望能夠切實的幫助到你。本篇將對CommenJS規范,node的文件模塊和核心模塊等做一個綜合的整理。如果你喜歡我的文章,歡迎評論,歡迎Star~。歡迎關注我的github博客
正文我覺得模塊的出現是js進步最大的地方。因為有了模塊,才使得很多優秀的東西可以真正被共享出來,而不用去擔心變量污染、命名空間的問題。
node作為一門服務端的javascript,它借鑒了CommonJS的規范,形成了一套易用的模塊規范。
首先,看看下面這個最常見的例子:
//circle.js const { PI } = Math; exports.area = x => PI*x**2; exports.circle = x => 2*PI*x;
//main.js const circle = require("./circle"); console.log(circle.area(4)); //50.26548245743669
其實,我們可以清晰地看到兩個文件中,模塊規范部分可以分成三部分:
require(模塊引用) => 這是整個模塊系統最核心的部分,能夠引入其他模塊,充分的運用。
exports(模塊定義) => 另一個出彩的地方,可以將自身模塊中的內容導出,供其他模塊使用。
標識(模塊標識) => 供別人認清楚模塊的東西。
這三塊內容可以使用一張圖片概括:
如圖:
從這幅圖中,我們可以看到,模塊之間可以通過exports將接口暴露出來,然后通過require來對另一個模塊內的內容進行引入。
這樣我們就大概懂得了模塊的定義。它主要分為三部分:模塊的引用、模塊定義和模塊標識。
然而,整個模塊部分我們最需要去了解的是require機制。node對于require實現,有很多的東西可以去欣賞。
首先,需要明白的是整個模塊引入的步驟。從上面的例子中,可以看出這三部分:
路徑分析 => 拿例子來進行分析的話,"./circle"就是路徑。(./此類的是相對路徑,當然還有絕對路徑)
文件定位 => 通過分析出來的位置,去進行文件的獲取。
編譯執行 => 只有通過編譯過的文件,才能夠放入其他模塊中進行使用 (之后也會分析如何進行編譯的)。
有的時候,情況是特殊的。模塊本身就分成核心模塊和文件模塊。而核心模塊在node源代碼編譯的時候。就被編譯成二進制文件。并且部分核心模塊會在node進程啟動時,直接加載到內存中,因此這一部分的核心模塊引入是不需要經過文件定位和編譯執行的步驟的。
還有特殊就是在緩存部分。每個模塊首次加載之后,node會緩存其編譯執行后的對象,方便二次加載。所以,二次加載時,是以緩存優先的,從緩存中加載的模塊也是不需要文件定位和編譯的。
單從路徑分析說起,可以分成三種不同的方式:
核心模塊,如http、fs、path等,加載優先級僅次于緩存加載,且會直接編譯成二進制文件
路徑形式的模塊,如上面例子中的‘./circle’。路徑明確,查找速度相對較快,加載速度慢于核心模塊
自定義模塊,大多如npm包形式的文件,存儲在node_modules,并沒有相應的路徑。這種查找比較繁瑣。
查找方式: 1. 從當前目錄下面的node_modules中查找是否具備相應的模塊 2. 若具備,則直接加載使用,否則,會去查找父目錄下的node_modules目錄,直至查找到根目錄下的node_modules中。這種方式是最慢的。
再來分析文件定位:
第一個例子中的標識符是"./circle"。可以發現,這個文件標識符是沒有后綴名的。那么,node是如何來進行定位的呢?其實,node有一個默認的定位順序:js、node、json。這里會最先識別js,之后一次對json和node的文件進行識別。因此,這里有個小技巧:在識別.node和.json的文件的時候,帶上文件后綴名會快一點, 為什么呢?是因為,node是使用fs同步阻塞的方式,逐一去嘗試,該文件是否存在,存在著直接加載;不存在的話,嘗試下一個后綴名。
還有對于那些自定義的模塊,如npm包。node的定位方式也是不同的。通常來說,npm包中都會具備package.json文件,這個文件中有個main屬性,這指向的就是整個包的入口文件;如果沒有這些條件,node會去默認加載index.js、index.json和index.node
最后就是模塊編譯部分的分析了:
首先,編譯執行也可以通過上面的三類后綴文件名來進行分析:
js文件 => 通過fs模塊同步讀取之后,編譯執行
node文件 => .node文件是c/c++文件模塊的編譯文件,使用dlopen的方法對文件進行加載引入。
json文件 => json文件首先是通過fs讀取文件,然后通過JSON.parse方法進行編譯執行。
其他后綴名的文件,都會被當成是js文件進行處理。同時,我們需要的細致地分析一下javascript文件編譯的一些具體過程。
javascript文件編譯
在使用fs讀取文件之后,讀取出來的內容node會如何去處理呢?會造成變量污染嗎?很顯然是不會的。node是根據CommonJS的規范,對讀取進入的內容,在頭部和尾部進行包裝,包裝成function(exports, require, module, __dirname,__filename){ ...讀取內容 }。這樣子,就起到了一個作用域隔絕的作用,不會對現有模塊中的內容污染。而__dirname、__filename是node中存在的。
然后將這個函數代碼使用vm原生的模塊runInThisContext()方法執行(類似eval => 將字符串轉化成可執行的js的代碼)。然后返回一個具體的對象,供現有模塊中的內容進行使用。
C/C++模塊的編譯
這個編譯主要是依靠node的process.dlopen()方法進行執行,同時node使用libuv對windows和*nix平臺做了兼容性的處理。這種模塊的性能相對于普通文件模塊來說較高,但是編寫成本也會相應地提高。
json文件編譯
json文件編譯會比較簡單,就是通過fs讀取文件,然后通過JSON.parse方法進行編譯,最終將內容給予現有模塊中命名的那個變量。
總結至此我們對node的模塊整體的機制,大致已經整理清楚了,從模塊的導出,到引入,以及標識符的分析。均可從CommonJS中找到影子,但是node對其進行的加工又相對比較完美。
如果你對我寫的有疑問,可以評論,如我寫的有錯誤,歡迎指正。你喜歡我的博客,請給我關注Star~呦。大家一起總結一起進步。歡迎關注我的github博客
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/89182.html
摘要:其中命令用于輸入其他模塊提供的功能,命令用于規定模塊的對外接口。 簡單記錄下自己對前端模塊化的一些淺薄理解,不對之處歡迎指正 在介紹前端模打包工具之前,我們先簡單說一下瀏覽器、v8和nodejs,因為我們現在用到的大部分前端模打包工具,都是需要nodejs環境運行的,同時他們都能通過npm進行下載 1. 瀏覽器: 瀏覽器組成可分兩部分:Shell+內核。瀏覽器內核又可以分成兩部分:渲染...
摘要:編寫一個簡單的程序,使其能接收一個或者多個命令行參數,并且在終端標準輸出中打印出這些參數的總和。處理所有可能發生的錯誤,并把它們傳遞給回調函數。編寫一個程序來發起一個請求,所請求的為命令行參數的第一個。 learnyounode 13課總結(上) 最近對nodejs比較感興趣,但是苦于無法下手,直接啃文檔又覺得十分生硬無趣。 幸好有熱心網友推薦了learnyounode這個好玩的入...
摘要:要想讓模塊再次運行,必須清除緩存。模塊加載的順序,按照其在代碼中出現的順序。最近參加了公司開展的一次培訓,結構性思維培養。 序言 模塊化,大家用vue,react等東西,都會接觸到像exports,module.exports,export,export default,require,define,import等等字段,感覺很多人對于這些東西還是分不清,概念非常的模糊,便想著寫這么一...
摘要:為指定事件注冊一個單次監聽器,即監聽器最多只會觸發一次,觸發后立刻解除該監聽器。移除指定事件的某個監聽器,監聽器必須是該事件已經注冊過的監聽器。返回指定事件的監聽器數組。如何創建空對象我們已經了解到,是要來儲存監聽事件監聽器數組的。 毫無疑問,nodeJS改變了整個前端開發生態。本文通過分析nodeJS當中events模塊源碼,由淺入深,動手實現了屬于自己的ES6事件觀察者系統。千萬不...
閱讀 3520·2021-11-25 09:43
閱讀 1279·2021-09-08 09:45
閱讀 2651·2021-09-07 09:59
閱讀 1515·2021-08-09 13:45
閱讀 3362·2019-08-30 15:54
閱讀 702·2019-08-29 18:35
閱讀 522·2019-08-29 17:18
閱讀 1004·2019-08-29 14:10