Node的模块实现

1. 路径分析
2. 文件定位
3. 编译执行

在Node中,模块分为两类:核心模块;文件模块

1. 优先从缓存加载
不论是核心模块还是文件模块,require()方法对相同模块的二次加载都一律采用缓存优先的方式(核心模块的缓存检查优先于文件模块)

2. 分析路径
1> 核心模块:
核心模块的优先级仅次于缓存加载,相同名称的文件模块,会加载失败,除非选择不同的标识符或换用路径
2> 路径形式的文件模块:
require()方法会先转为真实路径,并作为索引,然后把编译执行的结果放到缓存
3> 自定义模块:
特殊的文件模块,可能是个文件或者包;
模块路径的查找策略是:
一、当前文件目录下的node_modules目录
二、父级目录下的node_modules目录
三、父级目录的父级目录下的node_modules目录
......
是一种类似原型链的查找方式

3. 文件定位
1> 文件拓展名分析
会以.js/.json/.node的次序补足拓展名,依次尝试
2> 目录分析和包
优先查找目录下的package.json,通过JSON.parse()解析描述对象,取出其中main制定的文件名,进入文件拓展名分析
若找不到上述文件,会去查找index
还没有的话,会进入下一个模块路径重复上述查找

4. 模块编译
在Node中,每个文件模块都是一个对象,定义如下:
function Module(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/C++写的拓展文件,通过dlopen()方法加载编译生成的文件
— .json文件 通过fs模块读取后,用JSON.parse()解析
— 其他拓展名 都当做.js处理
编译成功的模块都会把文件路径作为索引缓存到Mudole._cache对象上
根据拓展名,Node会调用不同的读取方式
Mudule._extensions会被赋值给require()的extensions属性,通过在代码中访问require.extensions可以知道系统中已有的拓展加载方式
1> JavaScript模块的编译
在编译过程中,Node对获取的文件内容进行了头尾包装, 如下
(function(exports, require, module, __filename, __dirname){
var math = require('math')
exports.area = function(radius){
return Math.PI * radius * radius
}
})
2> C/C++模块的编译
调用process.dlopen()方法加载执行,在执行过程中,模块的exports对象与.node模块产生联系,返回给调用者
3> JSON文件的编译
利用fs模块同步读取JSON文件,调用JSON.parse()得到对象,赋给模块对象的exports,以供外部调用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值