如果是核心模块,比如path
等,在node源码编译的时候,已经编译进了二进制执行文件。在node启动时直接加载进内存中,所以跳过前两步,直接执行,加载速度最快。
文件模块则是在运行时动态加载,需要完整的路径分析,文件定位,编译执行,加载速度较慢。
文件模块执行过程
1. 路径分析
- 路径分析和文件定位
核心模块和路径形式的文件模块加载比较快。
主要分析自定义模块
当前文件目录下的node_modules目录
父目录下的node_modules
父目录的父目录下的node_modules
沿路径向上逐层查找知道根目录下的node_modules
它的生成方式与JavaScript的原型链和作用域链的查找方式十分类似。
2. 文件定位
commonJS模块规范允许标识符中不包含文件拓展名,这种情况下,Node会按照.js .json .node次序补足拓展名依次尝试。
在尝试过程中会调用fs模块同步阻断式的判断文件是否存在。Node又是单线程的,所以很容易想到的一个优化方案。在文件后面加上.node .json后缀会适当加速调用。
在这个过程中,Node对CommonJS包规范进行了- -定程度的支持。首先,Node在当前目录下
查找package.json ( CommonJS包规范定义的包描述文件),通过JSON.parse()解析出包描述对象,
从中取出main属性指定的文件名进行定位。如果文件名缺少扩展名,将会进人扩展名分析的步骤。
而如果main属性指定的文件名错误,或者压根没有package.json文件,Node会 将index当做默
认文件名,然后依次查找index.js、index.json、 index.node。
如果在目录分析的过程中没有定位成功任何文件,则自定义模块进人下-一个模块路径进行查
找。如果模块路径数组都被遍历完毕,依然没有查找到目标文件,则会抛出查找失败的异常。
3. 编译执行
.js文件。通过fs模块同步读取文件后编译执行。
.node文件。这是用C/C++编写的扩展文件,通过dlopen()方法加载最后编译生成的文件。
.json文件。通过fs模块同步读取文件后,用JSON. parse()解析返回结果。
其余扩展名文件。它们都被当做.js文件载人。
每一个编译成功的模块都作为索引缓存在Module._cache对象上,提高二次引入的性能