Node的模块儿查找机制

我心飞翔 分类:javascript

没有苦难的人生么有任何意义,为中华民族的伟大复兴而读书。

前情回顾

上篇文章主要分享了的一个commonJS规范的问题,那么今天接着昨天的话题继续聊一聊nodejs的模块儿查找机制

Node模块儿

在Node中引入模块,大致会经历这么几个过程:

  • 路径分析
  • 文件定位
  • 编译执行

在Node中,模块儿可以分为两大类,一类是Node提供的模块成为核心模块;另一类是用户编写的模块,成为文件模块

核心模块在Node源码编译的过程中,编译进了二进制执行文件中。当Node进程启动时,核心模块儿会直接被加载到内存中,所以核心模块引入时,文件定位和编译执行这两个步骤可以忽略掉,并且在路径分析中会优先判断,所以核心模块的加载速度是最快的

文件模块则是在运行中动态加载,需要完整的路径分析,文件定位,编译执行过程,加载速度比核心模块会慢一些。

模块儿加载过程

  • 优先从缓存中加载

Node对引入过的文件都会进行缓存,用来减少二次引用时的开销。与浏览器缓存不同的是,浏览器缓存的是文件,Node缓存的是编译和执行后的对象。

不论是核心模块还是文件模块,相同模块儿的二次加载都采用缓存优先的方式。但是核心模块的缓存检查优先级高于文件模块的缓存检查

路径分析和文件定位

不同的标识符,模块的查找及定位也有不同程度的差异。

    1. 模块标识符分析
    • 核心模块儿如 http,fs,path...
    • 绝对路径或相对路径
    • 自定义模块儿 或者可以理解为npm包

    核心模块的优先级仅次于缓存加载,它在Node源码中已经编译成二进制代码,所以其加载速度最快。

    绝对路径或相对路径这类标识符通常是我们自己写的文件模块儿,require()方法会将路径转为真实路径,并且以真实路径作为索引,将编译后的结果存放到缓存中,方便下载加载时更快。

    自定义模块儿 或者可以理解为npm包。 这类模块查找是最慢的,具体过程是这样的:当前目录的node_modules文件夹-->父目录下的node_modules文件夹-->递归查找父目录的node_modules-->直到根目录下的node_modules
    这过程跟JS的作用域链有些类似,但是文件层级越深,查找越耗时。

    1. 文件定位

    优先从缓存加载的策略时二次加载的效率得到了很大的提升,但是还需要考虑一些别的细节,比如:文件扩展名,目录的处理包的处理等等

    默认require()方法中的标识符不带扩展名,这种情况下Node会按照.js,.json,.node的顺序依次补足扩展名,依次尝试。

    这个过程中fs模块儿会同步阻塞式的判断文件是否存在。因为Node是单线程,所以会有一些性能上的问题,所以如果是json文件,带上扩展名,会多少提高一些性能。

    在分析标识符的过程中,require()通过分析扩展名之后,可能没有查到对应文件,但是却得到一个目录,此时Node会将这个目录当做一个包来处理。然后查找package.json,通过JSON.parse()解析出描述对象,然后从main属性指定的文件进行定位查找。没有扩展名则补齐扩展名,如果整个过程全布走完依然没有找到目标文件,则抛出异常。

下一篇简单聊一下模块如何编译及npm的相关知识点

总结

  • 优先从缓存加载
  • 递归查找

最后说两句

  1. 动一动您发财的小手,「点个赞吧」
  2. 动一动您发财的小手,「点个在看」
  3. 都看到这里了,不妨 「加个关注」
  4. 不妨 「转发一下」,好东西要记得分享

点击关注公众号

回复

我来回复
  • 暂无回复内容