在Node中,模块分为两类
- Node提供的内置模块,称之为核心模块
- 用户编写的自定义模块,称之为文件模块
而如果在Node中引入模块,主要经历三个步骤
- 路径分析
- 文件定位
- 编译执行
优先缓存加载
在Node中,如果是第二次通过require方法对模块进行引入,那么会采取优先缓存的方式。Node会将第一次编译和执行的对象放入缓存,提升效率。
而对于核心模块和文件模块,核心模块的检查优先于文件模块,例如你自己定义一个http,那么肯定是找不到滴。
路径分析
因为在Node中,是通过require来对模块进行引入的。而针对于不同的模块,查找和定位有不同程度上的差异。
(1)核心模块:主要是fs,http等模块。
核心模块的优先级仅次于缓存加载,它在Node的源代码编译中,加载过程最快。
(2)路径形式的文件模块:类似于require('./index.css')
这种文件模块,会被Node将路径转换为真实路径,用真实路径作为索引,将编译的结果存放到缓存中,一遍二次加载的时候速度更快。
(3)自定义模块:类似于require('mongose')
这种模块也一般都是通过npm进行下载安装的,它的查找是最费时的。而它的查找规则和JS中的原型链很像,不过不是__propto__,是通过node_modules一层层向上查找,直到找到目标文件为止。
文件定位
(1)文件扩展名分析
CommonJS允许在标识符中不存在文件扩展名,这个时候,Node会依次按.js,.json,.node给它拼上,然后在定位,尝试是否能给它找到。
由于Node是单线程,所以这个过程可能会引起性能问题
(2)目录分析包
有的时候,require引入的可能是一个文件夹,是一个目录。这个时候,Node会在这个文件夹中找到package.json文件,通过JSON.parse()解析出描述对象,拿到main属性指定的文件名进行定位。
如果没有找到呢,就会默认去找目录下的index,再一次按照.js,.json,.node进行查找。
如果这都没找到,那就G,抛出查找失败的异常。
模块编译
在Node中,每一个文件模块都是一个对象,它们的定义如下:
function Modal(id,parent){
this.id = id;
this.exports = {};
this.parent = parent;
if(parent && parent.children){
parent.children.push(this)
}
this.filename = null;
this.loaded = false;
this.children = []
}
对于不同的文件类型:
- .js文件:通过fs模块,同步读取文件后执行编译。
- .node文件:通过C++的dlopen()加载执行
- .json文件:通过JSON.parse()解析返回结果
- 其余扩展名:都被当做.js文件载入
require,exports,module这三个东西在哪放着
不仅是这三个,还有__filename,__dirname。他们都是从何而来的呢?
事实上,在编译的过程中,Node会对JS文件的内容进行包装一下,在头部加上一个(function (exports,require,module,__filename,__dirname) {\n
,在后面加上一个\n})
。文章来源:https://www.toymoban.com/news/detail-599757.html
(function (exports,require,module,__filename,__dirname) {
const math = require('math')
})()
给每个模块生成对应的方法,然后再将当前模块对象的这些属性和方法传进去。所以这些变量没有定义,但也能使用。文章来源地址https://www.toymoban.com/news/detail-599757.html
到了这里,关于Node的模块加载的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!