目录
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》

1.png

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脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
2 周前 By 尊渡假赌尊渡假赌尊渡假赌
仓库:如何复兴队友
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
4 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++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和tomcat区别 nodejs和tomcat区别 Apr 21, 2024 am 04:16 AM

Node.js和Tomcat的主要区别在于:运行时:Node.js基于JavaScript运行时,而Tomcat是Java Servlet容器。I/O模型:Node.js采用异步非阻塞模型,而Tomcat是同步阻塞的。并发处理:Node.js通过事件循环处理并发,而Tomcat使用线程池。应用场景:Node.js适用于实时、数据密集型和高并发应用程序,Tomcat适用于传统Java Web应用程序。

nodejs是后端框架吗 nodejs是后端框架吗 Apr 21, 2024 am 05:09 AM

Node.js 可作为后端框架使用,因为它提供高性能、可扩展性、跨平台支持、丰富的生态系统和易于开发等功能。

nodejs和vuejs区别 nodejs和vuejs区别 Apr 21, 2024 am 04:17 AM

Node.js 是一种服务器端 JavaScript 运行时,而 Vue.js 是一个客户端 JavaScript 框架,用于创建交互式用户界面。Node.js 用于服务器端开发,如后端服务 API 开发和数据处理,而 Vue.js 用于客户端开发,如单页面应用程序和响应式用户界面。

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是后端开发语言吗 nodejs是后端开发语言吗 Apr 21, 2024 am 05:09 AM

是的,Node.js 是一种后端开发语言。它用于后端开发,包括处理服务器端业务逻辑、管理数据库连接和提供 API。

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和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和java选哪个 nodejs和java选哪个 Apr 21, 2024 am 04:40 AM

Node.js 和 Java 在 Web 开发中各有优劣,具体选择取决于项目要求。Node.js 擅长实时应用程序、快速开发和微服务架构,而 Java 则在企业级支持、性能和安全性方面占优。

See all articles