深入理解Commonjs规范及Node模块实现

2020-06-17 06:46:25易采站长站整理

根据参数的不同格式,require命令去不同路径寻找模块文件

1、如果参数字符串以“/”开头,则表示加载的是一个位于绝对路径的模块文件。比如,require(‘/home/marco/foo.js’)将加载/home/marco/foo.js

2、如果参数字符串以“./”开头,则表示加载的是一个位于相对路径(跟当前执行脚本的位置相比)的模块文件。比如,require(‘./circle’)将加载当前脚本同一目录的circle.js

3、如果参数字符串不以“./“或”/“开头,则表示加载的是一个默认提供的核心模块(位于Node的系统安装目录中),或者一个位于各级node_modules目录的已安装模块(全局安装或局部安装)

[注意]如果是当前路径下的文件模块,一定要以./开头,否则nodejs会试图去加载核心模块,或node_modules内的模块


//a.js
console.log('aaa');

//b.js
require('./a');//'aaa'
require('a');//报错

【文件扩展名分析】

require()在分析标识符的过程中,会出现标识符中不包含文件扩展名的情况。CommonJS模块规范也允许在标识符中不包含文件扩展名,这种情况下,Node会先查找是否存在没有后缀的该文件,如果没有,再按.js、.json、.node的次序补足扩展名,依次尝试

在尝试的过程中,需要调用fs模块同步阻塞式地判断文件是否存在。因为Node是单线程的,所以这里是一个会引起性能问题的地方。小诀窍是:如果是.node和.json文件,在传递给require()的标识符中带上扩展名,会加快一点速度。另一个诀窍是:同步配合缓存,可以大幅度缓解Node单线程中阻塞式调用的缺陷

【目录分析和包】

在分析标识符的过程中,require()通过分析文件扩展名之后,可能没有查找到对应文件,但却得到一个目录,这在引入自定义模块和逐个模块路径进行查找时经常会出现,此时Node会将目录当做一个包来处理

在这个过程中,Node对CommonJS包规范进行了一定程度的支持。首先,Node在当前目录下查找package.json(CommonJS包规范定义的包描述文件),通过JSON.parse()解析出包描述对象,从中取出main属性指定的文件名进行定位。如果文件名缺少扩展名,将会进入扩展名分析的步骤

而如果main属性指定的文件名错误,或者压根没有package.json文件,Node会将index当做默认文件名,然后依次查找index.js、index.json、index.node

如果在目录分析的过程中没有定位成功任何文件,则自定义模块进入下一个模块路径进行查找。如果模块路径数组都被遍历完毕,依然没有查找到目标文件,则会抛出查找失败的异常

 访问变量

如何在一个模块中访问另外一个模块中定义的变量呢?