目錄
CommonJS概述
CommonJS的模組規格
Node的模組實作
使用ES-Module
首頁 web前端 js教程 什麼是CommonJS模組規格? Nodejs模組機制淺析

什麼是CommonJS模組規格? Nodejs模組機制淺析

Aug 16, 2021 am 10:12 AM
nodejs

什麼是CommonJS模組規格? Nodejs模組機制淺析

Node應用程式由模組組成,其模組系統借鑒了CommonJS模組規範,但是並未完全按照規範實現,而是根據自身需求增加了一些特性,算是CommonJS模組規格的一個變種。

CommonJS概述

CommonJS是社群提出的一種JavaScript模組化規範,可以說是 JS模組化歷程中最重要的一塊里程碑,它建構了一個美好的願景-JS能夠在任何地方運行,但其實由於它的模組是同步載入的,只適合在服務端等其他本機環境,並不適合瀏覽器端等需要非同步載入資源的地方。

為了能讓JS能夠在任何地方運行,CommonJS制定了一些介面規範,這些介面覆蓋了模組、二進位、Buffer# 、字元集編碼、I/O流、進程環境、檔案系統、socket、單元測試、web伺服器、網關、套件管理等等,雖然大部分都處於草案階段,但是其深深影響了Node的發展。

下圖表示了Node與瀏覽器、W3CCommonJS以及ECMAScript之間的關係,摘自《深入淺出NodeJS》

什麼是CommonJS模組規格? Nodejs模組機制淺析

CommonJS的模組規格

CommonJS的模組主要由模組引用模組定義模組標識三部分組成。

模組標識

模組標識對每個模組來說是唯一的,是它被引用時的依據,它必須是符合小駝峰命名的字串,或是檔案的相對路徑或絕對路徑。

require('fs')// fs是内建模块,执行时会被直接载入内存,无须路径标识
require('./moduleA')//导入当前目录的moduleA
require('../moduleB')// 导入上一个目录的moduleB
require('C://moduleC')// 绝对路径导入moduleC
登入後複製

模組引用

使用require()來引用一個模組,這個方法接受一個模組識別作為參數,以此引入一個模組的API到目前上下文。

const fs = require('fs')// 引入内建的fs模块
登入後複製

模組定義

有導入自然也有導出,要將目前上下文中的方法或變數作為模組導出,需要使用內建的module.exports對象,它是模組導出的唯一出口。

CommonJS規格規定,每個模組內部,module變數代表目前模組。這個變數是一個對象,它的exports屬性(即module.exports)是對外的介面。載入某個模組,其實是載入該模組的module.exports屬性。

// moduleA.js模块
let moduleA = {
    name:"moduleA"
}
module.exports = {
    moduleA
}

// moduleB.js模块
// 导入moduleA
const {moduleA} = require('./moduleA')
登入後複製

CommonJS模組的特性如下:

  • 每個模組有獨立的上下文,模組內的程式碼獨立執行,不會污染全域作用域。
  • 模組可以被多次加載,但是只會在第一次加載時運行,運行結果會被緩存,後續再加載相同模組會直接讀取緩存結果,緩存存儲在module. cache
  • 模組的載入會依照程式碼順序執行。

Node的模組實作

Node#導入模組需要經歷3個步驟:路徑分析 -> 檔案定位 -> 編譯執行:

  • 路徑分析:根據模組識別分析模組類型。

  • 檔案定位:根據模組類型和模組識​​別碼找到模組所處位置。

  • 編譯執行:將檔案編譯成機器碼執行,中間需要經過一連串轉換。

【推薦學習:《nodejs 教學》】

模組類型分為內建模區塊與使用者模組:

  • 內建模區塊:內建模區塊由Node提供,已經被編譯成二進位執行文件,在node執行時,內建模區塊會直接載入內存,因此我們可以直接引入,它的加載速度很快,因為它不需要經過文件定位和編譯執行這2個步驟。

  • 檔案模組:使用jsC 等寫的擴充模組,執行時需要先被編譯成二進位機器碼。需要經過上述三大步驟。

模組快取

#不管是內建模區塊還是檔案模組,node在第一次載入後都會將結果快取起來,下次載入相同模組時,會先從快取中查找,如果能查找到則直接從快取中讀取,快取的結果是模組編譯和執行後的對象,是所有模組中加載最快的。

路径分析

路径分析依据的是模块标识符,模块标识符有以下几种类型:

  • 内建模块标识,例如fspath等,不需要编译,node运行时被直接载入内存等待导入。
  • 相对路径模块标识:使用相对路径描述的文件模块
  • 绝对路径模块标识:使用绝对路径描述的文件模块
  • 自定义模块标识:通常是node_modules中的包,引入时也不需要写路径描述,node有一套算法来寻找,是所有模块标识中分析速度最慢的。

文件定位

文件定位主要包括文件扩展名分析、目录和包的处理。如果文件定位结束时都没找到任何文件,则会抛出文件查找失败的异常。

文件扩展名分析

由于模块标识可以不添加文件扩展名,因此Node会按.js.json.node的次序依次补足扩展名来尝试加载,尝试加载的过程需要调用fs模块同步阻塞式地判断文件是否存在,因此为了提高性能,可以在使用require()导入模块时,参数带上文件扩展名,这样会加快文件定位速度。

目录、包的处理

在分析文件扩展名时,可能得到的是一个目录,此时Node会将其作为一个包处理,用查找包的规则来查找:在当前目录下查找package.json,获得其中定义的main属性指定的文件名,以它来作为查找的入口,如果没有package.json,则默认将目录下的index当前默认文件名,然后依次查找index.jsindex.jsonindex.node

编译执行

编译和执行是模块导入的最后一个步骤,node会先创建一个Module实例,代表当前模块。它有以下属性:

  • module.id 模块的识别符,通常是带有绝对路径的模块文件名。
  • module.filename 模块的文件名,带有绝对路径。
  • module.loaded 返回一个布尔值,表示模块是否已经完成加载。
  • module.parent 返回一个对象,表示调用该模块的模块。
  • module.children 返回一个数组,表示该模块要用到的其他模块。
  • module.exports 表示模块对外输出的值。

通过文件定位得到的信息,Node再载入文件并编译。对于不同的文件扩展名,其载入方法也有所不同:

  • .js文件:通过fs模块同步读取文件后编译执行。
  • .node文件:这是C/C++编写的扩展文件,通过dlopen()方法加载。
  • .json文件:通过fs模块读取后,用JSON.parse()解析返回结果。
  • 其余扩展名一律当.js文件载入

每一个载入的模块都会被缓存,可以通过require.cache来查看。

使用ES-Module

目前,在node中使用ES-Module属于实验性功能,从8.5开始支持,执行时需要加上--experimental-modules参数。从12.17.0 LTS开始,去掉了--experimental-modules ,现在可以通过使用.mjs文件代替.js文件或在package.json中指定 typemodule 两种方式使用。

// package.json
{ 
    "name": "esm-project", 
    "version": "1.0.0", 
    "main": "index.js", 
    "type": "module", 
    ... 
}
登入後複製

ES-Module相比于CommonJSModule机制,最大不同是ES-Module对导出模块的变量、对象是动态引用,而且是在编译阶段暴露模块的导入接口,因此可以进行静态分析;而CommonJS-Module是运行时同步加载,且输出的是导出模块的浅拷贝。除此之外,ES-Module支持加载CommonJS-Module,而反过来则不行。

其次,Node 规定 ES6 模块之中不能使用 CommonJS 模块的特有的一些内部变量,这是因为ES-Module顶层this指向undefinedCommonJS模块的顶层this指向当前模块,而这些内部变量作为顶层变量能被直接使用。

CommonJS的内部变量有:

  • arguments
  • require
  • #module
  • ##exportsm
  • __filename
  • __dirname
##總結

  • #Node模組的載入是同步的,只有載入完成,才能執行後面的操作。

  • 每一個檔案就是一個模組,有自己的作用域。每個模組內部,module物件代表了目前模組,它的exports屬性作為目前模組的導出介面。

  • 導入的模組是導出模組的一個淺拷貝。

更多程式相關知識,請造訪:程式設計影片! !

以上是什麼是CommonJS模組規格? Nodejs模組機制淺析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

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

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

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

nodejs和vuejs區別 nodejs和vuejs區別 Apr 21, 2024 am 04:17 AM

Node.js 是一種伺服器端 JavaScript 執行時,而 Vue.js 是一個客戶端 JavaScript 框架,用於建立互動式使用者介面。 Node.js 用於伺服器端開發,如後端服務 API 開發和資料處理,而 Vue.js 用於用戶端開發,如單一頁面應用程式和響應式使用者介面。

nodejs是後端框架嗎 nodejs是後端框架嗎 Apr 21, 2024 am 05:09 AM

Node.js 可作為後端框架使用,因為它提供高效能、可擴展性、跨平台支援、豐富的生態系統和易於開發等功能。

nodejs怎麼連接mysql資料庫 nodejs怎麼連接mysql資料庫 Apr 21, 2024 am 06:13 AM

要連接 MySQL 資料庫,需要遵循以下步驟:安裝 mysql2 驅動程式。使用 mysql2.createConnection() 建立連接對象,其中包含主機位址、連接埠、使用者名稱、密碼和資料庫名稱。使用 connection.query() 執行查詢。最後使用 connection.end() 結束連線。

nodejs中的全域變數有哪些 nodejs中的全域變數有哪些 Apr 21, 2024 am 04:54 AM

Node.js 中存在以下全域變數:全域物件:global核心模組:process、console、require執行階段環境變數:__dirname、__filename、__line、__column常數:undefined、null、NaN、Infinity、-Infinity

nodejs安裝目錄裡的npm與npm.cmd檔有什麼差別 nodejs安裝目錄裡的npm與npm.cmd檔有什麼差別 Apr 21, 2024 am 05:18 AM

Node.js 安裝目錄中有兩個與 npm 相關的文件:npm 和 npm.cmd,區別如下:擴展名不同:npm 是可執行文件,npm.cmd 是命令視窗快捷方式。 Windows 使用者:npm.cmd 可以在命令提示字元中使用,npm 只能從命令列執行。相容性:npm.cmd 特定於 Windows 系統,npm 跨平台可用。使用建議:Windows 使用者使用 npm.cmd,其他作業系統使用 npm。

nodejs和java的差別大嗎 nodejs和java的差別大嗎 Apr 21, 2024 am 06:12 AM

Node.js 和 Java 的主要差異在於設計和特性:事件驅動與執行緒驅動:Node.js 基於事件驅動,Java 基於執行緒驅動。單執行緒與多執行緒:Node.js 使用單執行緒事件循環,Java 使用多執行緒架構。執行時間環境:Node.js 在 V8 JavaScript 引擎上運行,而 Java 在 JVM 上運行。語法:Node.js 使用 JavaScript 語法,而 Java 使用 Java 語法。用途:Node.js 適用於 I/O 密集型任務,而 Java 適用於大型企業應用程式。

nodejs是後端開發語言嗎 nodejs是後端開發語言嗎 Apr 21, 2024 am 05:09 AM

是的,Node.js 是一種後端開發語言。它用於後端開發,包括處理伺服器端業務邏輯、管理資料庫連接和提供 API。

nodejs和java選哪個 nodejs和java選哪個 Apr 21, 2024 am 04:40 AM

Node.js 和 Java 在 Web 開發中各有優劣,因此選擇取決於專案需求。 Node.js 擅長即時應用程式、快速開發和微服務架構,而 Java 則在企業級支援、效能和安全性方面佔優。

See all articles