多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
在编译所有C/C++文件之前,编译程序需要将所有的JavaScript模块文件编译为C/C++代码,此时是否直接将其便以为可执行代码了呢?其实不是。 ## 1.转存为C/C++代码 Node采用了V8附带的js2c.py工具,将所有内置的JavaScript代码(src/node.js和lib/*.js)转换成C++里的数组,生成node_natives.h头文件,相关代码如下: ~~~ namespace node{ const char node_native[]={47,47,..}; const char dgram_native[]={47,47,..}; const char console_native[]={47,47,..}; const char buffer_native[]={47,47,..}; const char querystring_native[]={47,42,..}; ... struct _native{ const char* name; const char* source; size_t source_len; }; static const struct _native natives[]={ {"node",node_native,sizeof(node_native)-1}, {"dgram",dgram_native,sizeof(dgram_native)-1}, ... }; } ~~~ 在这个过程中,JavaScript代码以字符串的形式存储在node命名空间中,是不可直接执行的。在启动Node进程时,JavaScript代码直接加载进内存中。在加载的过程中,JavaScript核心模块经历标识符分析后直接定位到内存中,比普通的文件模块从磁盘中一处一处查找要快很多。 ## 2.编译JavaScript核心模块 lib目录下的所有模块文件也没有定义require、module、exports这些变量。在引入JavaScript核心模块的过程中,也经历了头尾包装的过程,然后才执行和导出了exports对象。与文件模块有区别的地方在于:获取源码的方式(核心模块是从内存中加载的)以及缓存执行结果的位置。 JavaScript核心模块的定义如下面的代码所示,源文件通过process.binding('natives')取出,编译成功的模块缓存到NativeModule._cahce对象上,文件模块则要缓存到Module._cache对象上: ~~~ function NativeModule(id){ this.filename = id + '.js'; this.id = id; this.exports = {}; this.loaded = false; } NativeModule._source=process.binding('natives'); NativeModule._cache = {}; ~~~