在Node引入模块时,需要经历如下三个步骤
模块的种类
在Node 中模块主要分为两类:
- Node提供的模块,称为核心模块。
- 用户编写的模块,称为文件模块。
模块加载顺序
- 尽管核心模块与文件模块的优先级不同,但是都不会优先于从文件模块的缓存中加载已经存在的模块。
- 核心模块的优先级仅次于文件模块缓存的优先级。require方法在解析文件名之后,优先检查模块是否在核心模块列表中。以http模块为例,尽管在目录下存在一个http/http.js/http.node/http.json文件,require(“http”)都不会从这些文件中加载,而是从核心模块中加载。
- 当文件模块缓存中不存在,而且不是核心模块的时候,Node.js会解析require方法传入的参数,并从文件系统中加载实际的文件。
路径分析
require()方法接受一个标识符作为参数。
- 核心模块,如http,fs,path等。(加载速度最快)
- .或者..开始的相对路径模块。(加载速度慢于核心模块)
- 以/开始的绝对路径模块。(加载速度慢于核心模块)
- 非路径形式的文件模块(自定义模块),如自定义的connet模块。(加载速度最慢)
自定义模块的模块路径
自定义模块指的是非核心模块,也不是路径形式的标识符。它是一种特殊的文件模块,可能是一个文件或者包的形式。这类模块查找是最费时的,也是所有方式中最慢的。
模块路径:
模块路径是Node在定位文件模块的具体文件时指定的查找策略,具体表现为一个路径组成的数组。
如:
console.log(module.paths)
模块路径的生成规则为:
- 当前目录下的node_modules目录
- 父目录下的node_modules目录
- 父目录的父目录下的node_modules目录
- 沿路径向上逐级递归,直到根目录下的node_modules目录
在加载过程中Node会逐个尝试模块路径中的路径,直到找到目标文件为止。所以当前文件越深,模块的查找就越耗时间。这就是其查找慢的原因。
文件定位
文件扩展名分析:
require()方法在分析标识符的过程中,会出现标识符中不包含文件扩展名的情况。这种情况下Node会按照.js .json .node 次序补足扩展名,依次尝试。目录分析和包:
在分析标识符过程中,require()方法可能没有查找到对应的文件,但却得到一个目录,此时Node会将目录当成一个包处理。
- 首先Node在当前目录下查找package.json,通过JSON.parse()解析出包对象,从中取出main属性指定的文件名进行定位。如过文件名缺少扩展名则会进入扩展名分析步骤(.js .json .node 次序补足扩展名,依次尝试)。
- 如果main属性指定的文件名错误,或者没有package.json文件,Node将默认index为文件名,然后依次查找 index.js index.json index.node。
- 如果在目录分析的过程中没有定位成功任何文件,则自定义模块进入下一个模块路径进行查找。如果模块路径数组都被遍历完毕,依然没有找到目标文件,则会抛出错误。
参考
<<深入浅出Node>>