本文是对nodejs0.8.9版本的api开发手册解读.nodejs网址
模块(Modules)
stability:5 -locked
node有一个简单的模块加载机制.在node里面文件和模块是 一对一 对应的.例如,foo.js加载在同一文件夹下的circle.js模块.
foo.js的内容:
var circle = require('./circle.js');
console.log( 'The area of a circle of radius 4 is '
+ circle.area(4));
circle.js的内容:
var PI = Math.PI;
exports.area = function (r) {
return PI * r * r;
};
exports.circumference = function (r) {
return 2 * PI * r;
};
circle.js模块以导出了area()方法和circumference()方法.为了导出一个对象,需要加上指定的exports对象.
属于模块的变量是私有的.在这个例子中变量PI就是私有于circle.js.
模块机制是在require('module')模块中实现的.
环形加载(Cycles)
console.log('a starting');
exports.done = false;
var b = require('./b.js');
console.log('in a, b.done = %j', b.done);
exports.done = true;
console.log('a done');
b.js:
console.log('b starting');
exports.done = false;
var a = require('./a.js');
console.log('in b, a.done = %j', a.done);
exports.done = true;
console.log('b done');
main.js:
console.log('main starting');
var a = require('./a.js');
var b = require('./b.js');
console.log('in main, a.done=%j, b.done=%j', a.done, b.done);
当main.js加载a.js的时候,a.js依次需要加载b.js.在这时,b.js试着去加载a.js.为了防止一个无穷的循环(loop),一个未完成的a.js的副本的exports导出对象被返回到b.js模块.然后b.js完成加载,然后他的exports导出对象被提供给a.js模块.
$ node main.js
main starting
a starting
b starting
in b, a.done = false
b done
in a, b.done = true
a done
in main, a.done=true, b.done=true
如果你的程序里面有环形的模块依赖,确保制定相应的计划(意思是,确保在所有依赖的模块都加载完时在调用,避免在模块未加载完时,调用导致程序不可预期的结果).
/home/ry/projects/node_modules/bar.js
/home/ry/node_modules/bar.js
/home/node_modules/bar.js
/node_modules/bar.js
{ "name" : "some-library",
"main" : "./lib/some-library.js" }
如果当前程序路径是在./some-library目录下,则require('./some-library')将会试图加载路径./some-library/lib/some-library.js.
./some-library/index.js
./some-library/index.node
缓存(Caching)var EventEmitter = require('events').EventEmitter;
module.exports = new EventEmitter();
// Do some work, and after some time emit
// the 'ready' event from the module itself.
setTimeout(function() {
module.exports.emit('ready');
}, 1000);
在另一个文件里我们需要做:
var a = require('./a');
a.on('ready', function() {
console.log('module a is ready');
});
注意,这种分配对象到module.exports对象的操作一定要立刻执行,如果放在任何一个回调函数里面,将不会生效.
setTimeout(function() {
module.exports = { a: "hello" };
}, 0);
y.js
var x = require('./x');
console.log(x.a);
require(X) from module at path Y
1. If X is a core module,
a. return the core module
b. STOP
2. If X begins with './' or '/' or '../'
a. LOAD_AS_FILE(Y + X)
b. LOAD_AS_DIRECTORY(Y + X)
3. LOAD_NODE_MODULES(X, dirname(Y))
4. THROW "not found"
LOAD_AS_FILE(X)
1. If X is a file, load X as JavaScript text. STOP
2. If X.js is a file, load X.js as JavaScript text. STOP
3. If X.node is a file, load X.node as binary addon. STOP
LOAD_AS_DIRECTORY(X)
1. If X/package.json is a file,
a. Parse X/package.json, and look for "main" field.
b. let M = X + (json main field)
c. LOAD_AS_FILE(M)
2. If X/index.js is a file, load X/index.js as JavaScript text. STOP
3. If X/index.node is a file, load X/index.node as binary addon. STOP
LOAD_NODE_MODULES(X, START)
1. let DIRS=NODE_MODULES_PATHS(START)
2. for each DIR in DIRS:
a. LOAD_AS_FILE(DIR/X)
b. LOAD_AS_DIRECTORY(DIR/X)
NODE_MODULES_PATHS(START)
1. let PARTS = path split(START)
2. let ROOT = index of first instance of "node_modules" in PARTS, or 0
3. let I = count of PARTS - 1
4. let DIRS = []
5. while I > ROOT,
a. if PARTS[I] = "node_modules" CONTINUE
c. DIR = path join(PARTS[0 .. I] + "node_modules")
b. DIRS = DIRS + DIR
c. let I = I - 1
6. return DIRS
1: $HOME/.node_modules
2: $HOME/.node_libraries
3: $PREFIX/lib/node
$HOME是用户的home目录,$PREFIX是node配置的node_prefix.
require.main === module
/usr/lib/node/foo/1.2.3/ - Contents of the foo package, version 1.2.3.
/usr/lib/node/bar/4.3.2/ - Contents of the bar package that foo depends on.
/usr/lib/node/foo/1.2.3/node_modules/bar - Symbolic link to /usr/lib/node/bar/4.3.2/.
/usr/lib/node/bar/4.3.2/node_modules/* - Symbolic links to the packages that bar depends on.