浅析nodejs的require函数分别加载自定义模块和npm开源库的不同加载原理、NodeJS模块加载机制require和module的理解
2022/4/15 1:14:45
本文主要是介绍浅析nodejs的require函数分别加载自定义模块和npm开源库的不同加载原理、NodeJS模块加载机制require和module的理解,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
一、require 函数
1、require 函数是什么?
首先,直接说require函数的功能:用来加载目标js库,并返回目标js库公开的属性成员函数/变量。
我们在终端 node shell 输入 this.require === require,可以看到为 true
由此可得出结论:require是Node引擎上下文context的内置对象属性,也就是全局对象的require属性,可调用或者使用this.require也行。
2、require 加载 node 内置模块
我们都知道 require 可以用来加载 node 的内置模块。比如: require('fs') // 加载文件系统模块
3、那么非内置的模块,也想用require来加载,怎么做呢?
在当前目录下,我们新建一个 test.js,内容如图;然后,试着用require来加载看看。
require函数能够加载这个 test.js,不过不像内置模块一样,需要通过给文件路径来定位到该 js 文件,如:require('./test') 或 require('./test.js'),这里我们看到打印的对象没有任何属性,require返回值为 :{} // 没有任何属性
二、require 函数加载原理
由于NodeJS模块都遵循了CommonJS规范,根据CommonJS规范,JS库的开发者如果需要开发某些函数对外部模块使用,需要使用module.exports或者exports
具体如下:module.exports.属性名 = 函数引用 // 这里将当前JS内的某个函数赋给 module.exports
或者:exports.属性名 = 函数引用
上面那个 test.js 相当于
const products = {data:[]} function getData(){ return products.data; } //默认情况,module.exports 这个对象没有任何属性,如下代码 module.exports = {}
修改 test.js 文件,继续在终端跑 require('./test') 看,输出仍旧为:{}
为什么呢?我们明明修改了导出的内容啊?
这里先说一下结论:我们需要先退出当前node终端,重新进入终端,才可以导入修改后的内容。这里请思考一下为什么需要重新打开一个node REPL终端呢?
可以看到重新打开后,就可以获取到值了。再查看 require 发现上面多了很多东西。
三、怎么加载npm registry上的库?
比如输入require('lodash') 马上发现错误了,“Cannot find module 'lodash'",这个错误经常容易见到(有时候拿到一个NodeJS项目忘记跑npm install了)
通常我们需要使用命令安装JS库:npm install 目标JS库名,再来使用它共享的功能。
我们试试看,安装完lodash库之后,继续在Node终端输入require('lodash') 可以使用了,这里不需要重启(这又是为什么呢?为什么不需要重启呢?)。
1、为什么 node 终端能够加载到 test.js,export内部函数之后又需要重启,引入外部JS库又不需要重开一个Node REPL终端?
这里需要讲讲require的另一个伙伴:module函数。它跟require函数一样都挂载在上下文中,也是全局对象的一个属性,它的作用是管理整个项目的模块。
进入node终端,打印 module,可以显示模块加载的细节,这里稍微留意一下children(里面就有我们的 test.js 文件)。
2、解答”Cannot find module"问题
paths非空,我们使用require加载函数的时候,node引擎会从内置模块和paths对应的路径去查找模块,找不到才会抛出类似异常:“Cannot find module 'lodash'"
当我们跑了npm install 库名,对应模块被下载到node_module目录,加载的时候才能定位到库,正常使用该库功能
在含有package.json的目录中,执行npm install命令,可以一次性下载dependencies属性声明的全部依赖库
3、解答是否需要重启Node REPL?或者修改代码是否需要重启正在的NodeJS进程的问题?
继续在终端输入require('./test') ,然后输入module, 再次输出module对象,它的children已经多了一个Module对象(id对应到了test.js)
当我们修改了 test.js,再次 require("./test") 的时候,node引擎发现module对象已经记录加载过 test.js 了,不会重新进行加载。
所以,这也就是虽然我们最新代码导出了getData函数,可是我们加载到的仍旧是:{} 无任何函数导出的原因。
4、解答为何npm install lodash之后能够直接在node终端直接require就可以生效?
因为node启动,默认会查找到当前目录下的node_modules目录(不管目录存在不存在),当我们require一个不存在的js模块的时候,module对象找不到模块,它的children属性并不会有任何变动。
当安装了 lodash 后,它就会在 node_modules 里存在,当再次去查找时就可以查到了。因此npm上的开源ks库,我们只需要安装了,就可以require加载。
5、总结:
require和module互相协作产生的模块加载机制,是整个NodeJS开源文化的基石之一;而CommonJS就是一个脱离了框架的协议。这也在很多语言中反复出现,像python/java的import包,CommonJS就像一个包协议,约定了库的共享的标准格式,npm对标maven central/python libs。这套协议加上加载模式相关的接口模式,很值得借鉴。
这篇关于浅析nodejs的require函数分别加载自定义模块和npm开源库的不同加载原理、NodeJS模块加载机制require和module的理解的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-16Vue3资料:新手入门必读教程
- 2024-11-16Vue3资料:新手入门全面指南
- 2024-11-16Vue资料:新手入门完全指南
- 2024-11-16Vue项目实战:新手入门指南
- 2024-11-16React Hooks之useEffect案例详解
- 2024-11-16useRef案例详解:React中的useRef使用教程
- 2024-11-16React Hooks之useState案例详解
- 2024-11-16Vue入门指南:从零开始搭建第一个Vue项目
- 2024-11-16Vue3学习:新手入门教程与实践指南
- 2024-11-16Vue3学习:从入门到初级实战教程