Open abbshr opened 10 years ago
Module.prototype.require
添加进去, 不然module.require
无法解释.:thumbsup:
以NODE_MODULE_CONTEXTS
环境变量启动有个bug, 昨天给io.js提交了一个pull request https://github.com/iojs/io.js/pull/1160, 最后他们决定把NODE_MODULE_CONTEXTS=1
这个选项砍掉了.
https://github.com/iojs/io.js/pull/1162
所以下面这段代码删掉.
// 如果设置了环境变量NODE_MODULE_CONTEXTS=1, 各模块将在自己的上下文加载.
if (Module._contextLoad) {
// 如果加载的并非主模块,(别忘了主模块的id为".")
// 则在sandbox环境中运行代码
if (self.id !== '.') {
debug('load submodule');
// not root module
var sandbox = {};
for (var k in global) {
sandbox[k] = global[k];
}
sandbox.require = require;
sandbox.exports = self.exports;
sandbox.__filename = filename;
sandbox.__dirname = dirname;
sandbox.module = self;
sandbox.global = sandbox;
sandbox.root = root;
return runInNewContext(content, sandbox, { filename: filename });
}
// 否则就是主模块
debug('load root module');
// root module
global.require = require;
global.exports = self.exports;
global.__filename = filename;
global.__dirname = dirname;
global.module = self;
return runInThisContext(content, { filename: filename });
}
Node.js启动流程探秘
涉及源码
这篇日志的诞生纯属偶然,我当初只是想寻找NPM上处理底层网络的模块用来处理ARP协议,搜索了半天并没有发现合适的,最贴近的也就是raw_socket模块,但它只能用来处理IP协议上层和ICMP数据报.然后我就开始各种Google各种Baidu,未果.于是想自己扩充一下这个底层功能,便查找C/C++ addon的文档,这就一不小心"误入歧途"了,从学习addon到研究模块加载最后成了源码阅读.
也好,在这个时候从设计和编码的角度重审Node也别有一番体会.
拿来Node的源代码,熟悉源码构建编译的童鞋一眼就会发现
src
,lib
目录.这表示Node的源码结构很清晰,以下是源码目录的主要结构:deps/
Node核心功能的依赖,包括V8引擎源码,libuv源码,openssl,npm等等lib/
JavaScript核心模块(*.js),如http.js
,net.js
等src/
Node架构的核心源代码以及C++核心模块/内置模块(.cc | .h)tool/
包含Node的项目构建工具gyp,js2c.py等,用来编译源码生成二进制文件,预处理工作等node.gyp
重要的构建配置文件common.gyp
同样是一个配置文件为了了解Node工作流程,首先进入src目录,找到
node_main.cc
文件.整个文件的最后几行包含着令人倍感亲切的int main()
主函数,进程就从这里开始了:我将按照Node进程的真正流程一步步说明,因此下面代码中的嵌套有些地方并不是真实的代码结构,可以通过阅读我的注释明白情况.
接下来是
src/node.cc
文件,包含了主要的执行逻辑,node_main.cc
中调用的Start(argc, argv)
函数就是在这里面实现的:ok,还记得上面的整个流程中有一处代码是调用JavaScript文件
src/node.js
?已经说它是作为global对象的方法调用的,下面来看离我们最近的src/node.js源码:
以上,就是Node进程的启动流程,接下来的主题是Node中模块(module)的加载过程
模块化设计理念
涉及源码
模块引用是写Node程序时必有(可以这么说)的一个环节.先来看看高层模块加载系统lib/module.js的一部分源码:
下面详细分析lib/node.js中的模块加载部分:
看完上面这段源码,我想你会清楚Node环境下module对象的那些成员的来历了.下面同样来自src/node.js,是模块编译中掉用的
runInThisContext
函数的声明:我们再次回到C++的作用域,contextify内置模块的所属文件为
src/node_contextify.cc
:通过阅读前一部分src/node.js源码不难发现,在初始化环境时(startup函数最后的if分支部分)调用了:
也就是说在你的JavaScript代码执行之前,就已经存在了经过编译之后的module模块.
已经分析到这一步了,但是我们的"主模块",也就是通过
node app.js
执行的app.js
是如何加载的呢?注意src/node.js在条件分支的普通模式最后执行了:
下面我们继续解读lib/module.js的源码剩余部分:
到此为止,整个流程分析完毕,Node布置好一切并执行了程序.