目录
什么是CommonJs规范
首页 web前端 js教程 深入了解Node的模块机制,聊聊模块实现流程

深入了解Node的模块机制,聊聊模块实现流程

May 25, 2022 pm 09:12 PM
nodejs​ node.js node

本篇文章带大家了解一下CommonJs规范和Node的模块机制,介绍一下Node实现CommonJs规范的基本流程,希望对大家有所帮助!

深入了解Node的模块机制,聊聊模块实现流程

在CommonJs规范提出之前,Javascript是没有模块系统的,这意味着我们很难开发大型的应用,因为代码的组织会比较困难。

什么是CommonJs规范


首先CommonJS不是Node独有的东西,CommonJs是一种模块规范,定义了如何引用和导出模块,Nodejs只是实现了这个规范,CommonJS模块规范主要分为模块引用、模块定义和模块标识三个部分。

模块引用

模块引用就是我们可以通过require引入其它的模块。

const { add } = require('./add');
const result = add(1 ,2);
登录后复制

模块定义

一个文件就是一个模块,模块里会提供两个变量,分别为module和exports。module为当前模块本身,exports为要导出的内容,同时exports为module的一个属性,即exports为module.exports。其他模块通过require导入的内容即为module.exports的内容。

// add.js
exports.add = (a, b) => {
    return a + b;
}
登录后复制
登录后复制

模块标识

模块标识即为require里面的内容,比如require('./add'),则模块标识为./add

通过CommonJS构建的这套模块导入导出机制使得用户完全无需考虑变量污染,可以方便的构建大型应用。

Node的模块实现


Node实现了CommonJs规范,并且增加了一些自己需要的特性。Node为了实现CommonJs规范主要做了以下三件事情:

  • 路径分析

  • 文件定位

  • 编译执行

路径分析

当执行require()的时候,require接收的参数即为模块标识符,node通过模块标识符来进行路径分析。路径分析的目的就是为了通过模块标识符找到这个模块所在的路径。首先,node的模块分为两类,分别是核心模块和文件模块。核心模块是node自带的模块,文件模块是用户编写的模块。同时文件模块又分为相对路径形式的文件模块、绝对路径形式的文件模块和非路径形式的文件模块(比如express)。

未命名文件.png

当node找到一个文件模块之后,会将这个模块编译执行并且缓存起来,大致原理是将这个模块的完整路径作为key,编译后的内容作为值,后续再第二次引入这个模块的时候就不需要再进行路径分析文件定位编译执行这几个步骤了,可以直接从缓存中读取编译好的内容。

// 缓存的模块示意:
const cachedModule = {
    '/Usr/file/src/add.js': 'add.js编译后的内容',
    'http': 'Node自带的http模块编译后的内容',
    'express': '非路径形式自定义文件模块express编译后的内容'
    // ...
}
登录后复制

当要查找require导入的模块时,查找模块的顺序是先查看缓存里是否已经有该模块,如果缓存里面没有再查看核心模块,然后再查找文件模块。其中路径形式的文件模块比较好查找,根据相对或绝对路径就可以得到完整的文件路径。非路径形式的自定义文件模块查找起来会相对麻烦一些,Node会从node_modules这个文件夹里去查找是否有这个文件。

node_modules这个目录在哪里呢,比如说我们当前执行的文件为/Usr/file/index.js;

/** 
* /Usr/file/index.js;
*/

const { add } = require('add');
const result = add(1, 2);
登录后复制

这个模块里我们有引入了一个add模块,这个add不是一个核心模块也不是一个路径形式的文件模块,那么这时候如何找到这个add模块呢。

module有一个paths的属性,查找add模块的路径在paths这个属性里,我们可以把这个属性打出来看一下:

/** 
* /Usr/file/index.js;
*/

console.log(module.paths);
登录后复制

我们在file目录下执行node index.js可以打印出paths的值。paths里的值是一个数组,如下:

[
'/Usr/file/node_modules',
'/Usr/node_modules',
'/node_modules',
]
登录后复制

即Node会依次从上面的目录里寻在是否包含add这个模块,原理和原型链类似。先从当前执行的文件的同级目录的node_modules文件夹里开始找,如果没找到或者没有node_modules这个目录,则继续往上级查找。

文件定位

路径分析和文件定位是搭配一起使用的,文件标识符可以是不带后缀的,也可能通过路径分析找到的是一个目录或者一个包,这个时候要定位到具体的文件需要一些额外的处理。

文件扩展名分析

const { add } = require('./add');
登录后复制

比如上面这段代码,文件标识符是不带扩展名的,这个时候node会依次查找是否存在.js、.json、.node文件。

目录和包分析

同样是上面这段代码,通过./add查找到的可能不是一个文件,可能是一个目录或者包(通过判断add文件夹下是否有package.json文件来判断是目录还是包)。这个时候文件定位的步骤是这样的:

  • 查看是否有package.json文件
      • 读取package.json里的main字段的值作为文件
    • 没有
      • 寻找目录下的index作为文件(依次查找index.js、index.json、index.node)

如果package.json里没有main字段,那么也会将index作为文件,然后进行扩展名分析找到对应后缀的文件。

模块编译

我们开发中主要遇到的模块为json模块和js模块。

json模块编译

当我们require一个json模块的时候,实际上Node会帮我们使用fs.readFilcSync去读取对应的json文件,得到json字符串,然后调用JSON.parse解析得到json对象,再赋值给module.exports,然后给到require。

js模块编译

当我们require一个js模块的时候,比如

// index.js
const { add } = require('./add');
登录后复制
// add.js
exports.add = (a, b) => {
    return a + b;
}
登录后复制
登录后复制

这个时候发生了什么呢,为什么我们可以直接在模块里使用module、exports、require这些变量。这是因为Node在编译js模块的时候对模块的内容进行了首尾的包装。

比如add.js这个模块,实际编译的时候是会被包装成类似这样的结构:

(function(require, exports, module) {
  exports.add = (a, b) => {
    return a + b;
  }
  return module.exports;
})(require, module.exports, module)
登录后复制

即我们编写的js文件是会被包装成一个函数,我们编写的只是这个函数里的内容,Node后续的包装的过程对我们隐藏了。这个函数支持传入一些参数,其中就包括require、exports和module。

当编译完js文件后,就会执行这个文件,node会将对应的参数传给这个函数然后执行,并且返回module.exports值给到require函数。

以上就是Node实现CommonJs规范的基本流程。

更多node相关知识,请访问:nodejs 教程

以上是深入了解Node的模块机制,聊聊模块实现流程的详细内容。更多信息请关注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.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前 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)

一文聊聊Node中的内存控制 一文聊聊Node中的内存控制 Apr 26, 2023 pm 05:37 PM

基于无阻塞、事件驱动建立的Node服务,具有内存消耗低的优点,非常适合处理海量的网络请求。在海量请求的前提下,就需要考虑“内存控制”的相关问题了。 1. V8的垃圾回收机制与内存限制 Js由垃圾回收机

图文详解Node V8引擎的内存和GC 图文详解Node V8引擎的内存和GC Mar 29, 2023 pm 06:02 PM

本篇文章带大家深入了解NodeJS V8引擎的内存和垃圾回收器(GC),希望对大家有所帮助!

深入聊聊Node中的File模块 深入聊聊Node中的File模块 Apr 24, 2023 pm 05:49 PM

文件模块是对底层文件操作的封装,例如文件读写/打开关闭/删除添加等等 文件模块最大的特点就是所有的方法都提供的**同步**和**异步**两个版本,具有 sync 后缀的方法都是同步方法,没有的都是异

node项目中如何使用express来处理文件的上传 node项目中如何使用express来处理文件的上传 Mar 28, 2023 pm 07:28 PM

怎么处理文件上传?下面本篇文章给大家介绍一下node项目中如何使用express来处理文件的上传,希望对大家有所帮助!

深入浅析Node的进程管理工具“pm2” 深入浅析Node的进程管理工具“pm2” Apr 03, 2023 pm 06:02 PM

本篇文章给大家分享Node的进程管理工具“pm2”,聊聊为什么需要pm2、安装和使用pm2的方法,希望对大家有所帮助!

Pi Node教学:什么是Pi节点?如何安装和设定Pi Node? Pi Node教学:什么是Pi节点?如何安装和设定Pi Node? Mar 05, 2025 pm 05:57 PM

PiNetwork节点详解及安装指南本文将详细介绍PiNetwork生态系统中的关键角色——Pi节点,并提供安装和配置的完整步骤。Pi节点在PiNetwork区块链测试网推出后,成为众多先锋积极参与测试的重要环节,为即将到来的主网发布做准备。如果您还不了解PiNetwork,请参考Pi币是什么?上市价格多少?Pi用途、挖矿及安全性分析。什么是PiNetwork?PiNetwork项目始于2019年,拥有其专属加密货币Pi币。该项目旨在创建一个人人可参与

一起聊聊Node中的事件循环 一起聊聊Node中的事件循环 Apr 11, 2023 pm 07:08 PM

事件循环是 Node.js 的基本组成部分,通过确保主线程不被阻塞来实现异步编程,了解事件循环对构建高效应用程序至关重要。下面本篇文章就来带大家深入了解Node中的事件循环 ,希望对大家有所帮助!

node无法用npm命令怎么办 node无法用npm命令怎么办 Feb 08, 2023 am 10:09 AM

node无法用npm命令是因为没有正确配置环境变量,其解决办法是:1、打开“系统属性”;2、找到“环境变量”->“系统变量”,然后编辑环境变量;3、找到nodejs所在的文件夹;4、点击“确定”即可。

See all articles