Skip to main content

内置模块

CommonJS 规范

模块的定义

上下文提供了 exports 对象用于导出当前模块的方法或者变量,并且它是位移导出的出口。

在模块中还存在一个 module 对象,它代表模块自身,而 exports 是 module 的属性。一个文件就是一个模块,将方法挂载在 exports 对象上作为属性即可定义导出的方式。

模块的实现

分三个步骤

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

Node 提供的模块叫做核心模块,用户编写的模块叫做文件模块。

核心模块在 Node 源代码编译的过程中,编译进了二进制执行文件,在 Node 进程启动的时候部分核心模块就被直接加载进内存中,所以在这部分核心模块引入的时候,文件定位和编译执行这两个阶段可以省略,并且在路径分析中优先判断,加载速度最快。

  • 优先从缓存加载
  • 路径分析和文件定位

文件定位 文件年扩展名分析

模块编译

在 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 = [];
}

每一个编译成功的模块都会将文件路径作为索引存在 Module._cache 对象上

Module._extensions['json'] = function(module, filename) {
var content = NativeModule.require('fs').readFielSync(filename, 'utf8');
try {
module.exports = JSON.parse(stripBOM(content));
} catch(err) {
err.message = filename + ':' + err.message;
throw err;
}
}

核心模块

编译过程

将编译所有 CC++文件之前,将所有 js 模块文件编译为CC++代码。

  • 转成为C/C++代码

Node 采用 V8 附带的 js2c.py 工具,将所有内置的 Javascript 代码,转换成 C++ 里的数组,生成 node_natives.h 头文件。

js 代码以字符串的形式存储在 node 命名空间中,是不可执行的。在启动 Node 进程时,js 代码直接加载进内存中,核心模块经历标识符分析后直接定位到内存中,比普通的文件模块从磁盘中一处一处查找要快的多。

  • 编译核心模块

纯CC++编写的部分称为内建模块,通常不被用户直接调用。Node 的 buffer、crypto、evals、fs、os 等模块都是部分通过 CC++ 编写的。

内建模块的结构定义

struct node_module_struct {
int version;
void *dso_handle;
const char *filename;
void (*register_fun) (v8::Handle<v8::Object> target);
const char *modname;
}