ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

浅析nodejs的require函数分别加载自定义模块和npm开源库的不同加载原理、NodeJS模块加载机制require和module的理解

2022-04-14 22:32:01  阅读:150  来源: 互联网

标签:node require module js 模块 test 加载


一、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。这套协议加上加载模式相关的接口模式,很值得借鉴。

标签:node,require,module,js,模块,test,加载
来源: https://www.cnblogs.com/goloving/p/16144137.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有