Node
The application is composed of modules. Its module system draws on the CommonJS
module specification, but it is not implemented completely in accordance with the specification, but according to Some features have been added for its own needs, which can be regarded as a variant of the CommonJS
module specification.
CommonJS
is a JavaScript
modular specification proposed by the community, which can be said to be The most important milestone in the modularization process of JS
, it constructs a beautiful vision-JS
can run anywhere, but in fact, because its modules are loaded synchronously, it is only suitable for Other local environments such as the server are not suitable for browsers and other places that need to load resources asynchronously.
In order to enable JS
to run anywhere, CommonJS
has developed some interface specifications, which cover modules, binaries, Buffer
, character set encoding, I/O
streams, process environment, file system, socket
, unit testing, web server, gateway, package management, etc., although most of them are in the draft stage , but it has deeply affected the development of Node
.
The following figure shows the relationship between Node
and the browser, W3C
, CommonJS
and ECMAScript
, excerpted from "In-depth introduction to NodeJS"
##The modules of CommonJS are mainly composed of
modules It consists of three parts: reference , module definition and module identification .
Module identification
The module identification is unique for each module and is the basis for it to be referenced. It must comply with A camelCase named string that is either a relative or absolute path to a file.require('fs')// fs是内建模块,执行时会被直接载入内存,无须路径标识 require('./moduleA')//导入当前目录的moduleA require('../moduleB')// 导入上一个目录的moduleB require('C://moduleC')// 绝对路径导入moduleC
Module reference
Userequire() to reference a module. This method accepts a module identifier as a parameter , thereby introducing a module's API into the current context.
const fs = require('fs')// 引入内建的fs模块
Module definition
There are imports and exports. To export methods or variables in the current context as modules, you need to use built-in Themodule.exports object, which is the only export exported by the module.
CommonJSThe specification stipulates that inside each module, the
module variable represents the current module. This variable is an object, and its
exports attribute (that is,
module.exports) is the external interface. Loading a module actually loads the
module.exports attribute of the module.
// moduleA.js模块 let moduleA = { name:"moduleA" } module.exports = { moduleA } // moduleB.js模块 // 导入moduleA const {moduleA} = require('./moduleA')
CommonJSThe characteristics of the module are as follows:
modules in cacheNodeImporting the module requires
3 steps:
Path Analysis -> File location -> Compile execution:
nodejs Tutorial"]
Module types are divided into built-in modules and user modules:Node and has been compiled into a binary executable file. When
node is executed, the built-in module will be loaded directly Memory, so we can introduce it directly, and its loading speed is very fast, because it does not need to go through file location and compilation to perform these
2 steps.
js or
C needs to be compiled into binary machine code first when executed. You need to go through the above three steps.
Module cache
Whether it is a built-in module or a file module,node is in the After a load, the result will be cached. The next time the same module is loaded, it will be searched from the cache first. If it can be found, it will be read directly from the cache. The cached result is the object after the module is compiled and executed, and is all The fastest loading module.
路径分析
路径分析依据的是模块标识符,模块标识符有以下几种类型:
fs
,path
等,不需要编译,node
运行时被直接载入内存等待导入。node_modules
中的包,引入时也不需要写路径描述,node
有一套算法来寻找,是所有模块标识中分析速度最慢的。文件定位
文件定位主要包括文件扩展名分析、目录和包的处理。如果文件定位结束时都没找到任何文件,则会抛出文件查找失败的异常。
文件扩展名分析
由于模块标识可以不添加文件扩展名,因此Node
会按.js
、.json
、.node
的次序依次补足扩展名来尝试加载,尝试加载的过程需要调用fs
模块同步阻塞式地判断文件是否存在,因此为了提高性能,可以在使用require()
导入模块时,参数带上文件扩展名,这样会加快文件定位速度。
目录、包的处理
在分析文件扩展名时,可能得到的是一个目录,此时Node
会将其作为一个包处理,用查找包的规则来查找:在当前目录下查找package.json
,获得其中定义的main
属性指定的文件名,以它来作为查找的入口,如果没有package.json
,则默认将目录下的index
当前默认文件名,然后依次查找index.js
、index.json
、index.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
来查看。
目前,在node
中使用ES-Module
属于实验性功能,从8.5
开始支持,执行时需要加上--experimental-modules
参数。从12.17.0 LTS
开始,去掉了--experimental-modules
,现在可以通过使用.mjs
文件代替.js
文件或在package.json
中指定 type
为 module
两种方式使用。
// package.json { "name": "esm-project", "version": "1.0.0", "main": "index.js", "type": "module", ... }
ES-Module
相比于CommonJS
的Module
机制,最大不同是ES-Module
对导出模块的变量、对象是动态引用,而且是在编译阶段暴露模块的导入接口,因此可以进行静态分析;而CommonJS-Module
是运行时同步加载,且输出的是导出模块的浅拷贝。除此之外,ES-Module
支持加载CommonJS-Module
,而反过来则不行。
其次,Node
规定 ES6
模块之中不能使用 CommonJS
模块的特有的一些内部变量,这是因为ES-Module
顶层this
指向undefined
,CommonJS
模块的顶层this
指向当前模块,而这些内部变量作为顶层变量能被直接使用。
CommonJS
的内部变量有:
arguments
require
m
NodeThe loading of the module is synchronous. Only when the loading is completed can subsequent operations be performed.
module object represents the current module, and its
exports attribute serves as the export interface of the current module.
Programming Video! !
The above is the detailed content of What is the CommonJS module specification? A brief analysis of Nodejs module mechanism. For more information, please follow other related articles on the PHP Chinese website!