Node.js中的模組機制學習筆記_node.js
Javascript自誕生以來,曾經沒有人拿它當做一門程式語言。在Web 1.0時代,這種腳本語言主要被用來做表單驗證和網頁特效。直到Web 2.0時代,前端工程師利用它大大提升了網頁上的使用者體驗,JS才被廣泛重視。在JS逐漸流行的過程中,它大致經歷了工具類別庫、元件庫、前端框架、前端應用的變化。 Javascript先天缺乏一項功能:模組,而CommonJS規範的出現則彌補了這個缺陷。本文將介紹CommonJS規格及Node的模組機制。
在其他高階語言中,Java有類別文件,Python有import機制,PHP有include和require。而JS透過<script>標籤引入程式碼的方式顯得雜亂無章。過去人們不得不用命名空間等方式來人為地約束程式碼,直到CommonJS規格的出現,前後端的Javascript才得以實現大一統。 Node借鑒了CommonJS的Modules規格實作了一套非常易用的模組系統。 </script>
1. CommonJS模組規格
CommonJS的模組規格分為3個部分:
1).模組引用:透過require()方法並傳入一個模組標識來引入一個模組的API到當前上下文中,如var math = require('math');
2).模組定義:透過exports物件來導出目前模組的方法或變數。模組中還存在一個module對象,exports其實是module的屬性。在Node中,一個檔案就是一個模組,模組內的「全域變數」對外都不可見,只有掛載在exports上的屬性才是公開的,如exports.add = function() {}; exports.PI = 3.1415926;
3).模組標識:實際上就是傳遞給require()的參數,如上述的'math',它必須是符合camel命名法的字串,或者是以“.”“..”開頭的相對路徑或絕對路徑,它可以沒有檔名後綴“.js”
2. Node模組實作過程
在Node中,模組分為兩類:一類是Node本身提供的核心模組,另一類是使用者自己寫的檔案模組。核心模組有一部分在Node原始碼的編譯過程中,編譯成了二進位文件,在Node啟動時核心模組就被直接載入進記憶體中,所以它的載入速度是最快的。文件模組則是在運行時動態加載,需要經歷三個步驟:路徑分析,文件定位,編譯執行。請注意,Node對引入過的模組都會進行緩存,以減少二次引入時的開銷,並對相同模組的二次加載都採用最優先從緩存加載的策略。
2.1 路徑分析
路徑分析主要分析上述提到的模組標識符,主要分為以下幾類:
1)、核心模組,如http、fs、path等
2)、.或..開始的相對路徑檔模組
3)、以/開始的絕對路徑檔模組
4)、自訂檔案模組,可能是一個檔案或套件的形式。 Node會根據模組路徑數組module.paths來逐一嘗試查找目標文件,通常是沿著當前目錄逐級向上直到根目錄查找名為node_modules的目錄,所以這是查找最費時的一種方式。
2.2 檔案定位
在路徑分析的基礎上,檔案定位需要注意以下細節:
1)、檔案副檔名分析:由於CommonJS規格允許模組識別不填入副檔名,Node會按.js、.json、.node的次序不足副檔名,依序嘗試
2)、目錄分析和套件:若經過上述文件副檔名分析後沒有查找到對應文件,卻得到一個目錄,Node會把目錄當作一個包來處理
2.3 編譯執行
定位到特定檔案後,Node會新建一個模組對象,依照路徑載入並編譯。對於不同的副檔名,載入方法有所不同:
1)、.js檔:透過fs模組同步讀取檔並編譯執行
2)、.node檔:這是用C/C 寫的擴充文件,透過dlopen()方法載入
3)、.json檔:透過fs模組同步讀取文件,用JSON.parse()解析回傳結果
4)、其餘副檔名檔:都被當做.js檔載入
我們知道每個模組檔案中預設都存在著require、exports、module這3個變量,甚至在Node的API文件中,我們知道每個模組還有filename、dirname這2個變數的存在,它們是從何而來的呢? Node的模組又是怎麼做到宣告的「全域變數」其實是不會污染到其他模組的?事實上,Node在編譯JS模組過程中會對檔案內容進行頭尾包裝。下面是一個JS檔案經過頭尾包裝的範例:
(function(exports, require, module, __filename, __dirname) {
/* 中間是JS檔案的實際內容 */
var math = require('math');
exports.area = function(radius) {
return Math.PI * radius * radius;
};
/* JS檔案的實際內容結束 */
});
這樣每個模組檔案之間都進行了作用域隔離,同時require、exports、module等變數也被注入到了模組的上下文當中。這就是Node對CommonJS模組規範的實作。關於C/C 模組及Node核心模組的編譯過程較為複雜,不再贅述。
3. 模組呼叫堆疊
有必要先明確Node中各種模組的呼叫關係,如下圖所示:
C/C 內建模區塊是最底層的模組,屬於核心模組,主要提供API給Javascript核心模組和第三方Javascript檔案模組調用,實際上幾乎不會接觸到此類模組。 Javascript核心模組主要職責有兩種:一種是作為C/C 內建模塊的封裝層和橋接層供文件模組調用,另一種是純粹的功能模組,不需要跟底層打交道。文件模組通常由第三方編寫,包括普通Javascript模組和C/C 擴充模組。
4. 包與NPM
4.1 套件結構
套件本質上是一個存檔檔案(一般為.zip或.tar.gz),安裝後解壓縮還原為目錄。 CommonJS的包規格由包結構和包描述文件兩部分組成。一個完全符合CommonJS規範的套件結構應包含以下檔案:
1).package.json:套件描述檔
2).bin:存放可執行二進位的目錄
3).lib:存放Javascript程式碼的目錄
4).doc:存放文件的目錄
5).test:存放單元測試用例的目錄
4.2 包裝描述檔
套件描述檔是一個JSON檔案-package.json,位於套件的根目錄下,是套件的重要組成部分,用於描述套件的概況資訊。後面要提到的NPM的所有行為都與這個文件的欄位息息相關。以下將以知名Web框架express專案的package.json檔案為例說明一些常用欄位的意義。
1).name:包名
2).description:包簡介
3).version:版本號,需遵照“語意化的版本控制”,參考http://semver.org/
4).dependencies:使用目前套件所需依賴的套件清單。這個屬性十分重要,NPM會透過這個屬性自動載入依賴的套件
5).repositories:託管原始碼的位置清單
其餘欄位的用法可以參考NPM package.json說明
4.3 NPM常用功能
NPM(node package manager),通常稱為node套件管理器。它的主要功能是管理node包,包括:安裝、解除安裝、更新、檢視、搜尋、發布等。
4.3.1 NPM套件安裝
Node包的安裝分為兩種:本機安裝、全域安裝。兩者的差異如下:
1).本機安裝npm install
2).全域安裝npm install -g
4.3.2 NPM套件管理
以下以grunt-cli(grunt命令列工具)為例,列出常用的套件管理指令:
1).npm install:安裝package.json檔案的dependencies和devDependencies欄位宣告的所有套件
2).npm install grunt-cli@0.1.9:安裝特定版本的grunt-cli
3).npm install grunt-contrib-copy --save:安裝grunt-contrib-copy,同時保存該依賴到package.json檔案
4).npm uninstall grunt-cli:卸載套件
5).npm list:查看安裝了哪些套件
6).npm publish

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

基於無阻塞、事件驅動建立的Node服務,具有記憶體消耗低的優點,非常適合處理海量的網路請求。在海量請求的前提下,就需要考慮「記憶體控制」的相關問題了。 1. V8的垃圾回收機制與記憶體限制 Js由垃圾回收機

選擇一個Node的Docker映像看起來像是小事,但是映像的大小和潛在漏洞可能會對你的CI/CD流程和安全造成重大的影響。那我們要如何選擇一個最好Node.js Docker映像呢?

Node 19已正式發布,以下這篇文章就來帶大家詳解了解Node.js 19的 6 大特性,希望對大家有幫助!

文件模組是對底層文件操作的封裝,例如文件讀寫/打開關閉/刪除添加等等文件模組最大的特點就是所有的方法都提供的**同步**和**異步**兩個版本,具有sync 字尾的方法都是同步方法,沒有的都是異

事件循環是 Node.js 的基本組成部分,透過確保主執行緒不被阻塞來實現非同步編程,了解事件循環對建立高效應用程式至關重要。以下這篇文章就來帶大家深入了解Node中的事件循環 ,希望對大家有幫助!

一開始的時候 JS 只在瀏覽器端運行,對於 Unicode 編碼的字串容易處理,但對於二進位和非 Unicode 編碼的字串處理困難。並且二進制是電腦最底層的資料格式,視訊/音訊/程式/網路包
