译者:CommonJS Modules/1.0 是目前JavaScript模块化的事实标准,虽然其已经被 CommonJS Modules/1.1 所替代,但是1.0的适用范围非常广,支持者也很多,其中包括Flusspferd, GLUEscript, GPSEE, JSBuild, Narwhal (0.1), Persevere, RingoJS, SproutCore 1.1/Tiki, node.js, TeaJS (formerly v8cgi), CouchDB, Smart Platform, Yabble, Wakanda, XULJet等,所以翻译此规范还是很有必要的,以下为正文。
此规范指出了如何编写可以在同类模块系统中所共用的模块,这类模块系统可以同时在客户端和服务端,以安全的或者不安全的方式已经被实现了或者通过语法扩展可以被未来的系统所支持。这些模块需要提供顶级作用域的私有性,并提供从其他模块导入单例对象到自身并且可以导出自身API的能力。含蓄的说,这个规范定义了如果一个模块系统要支持共用模块,那么它需要提供的最少的功能特性。
#契约
##模块上下文
##模块标识符
##未规范 此规范对如下关于协同工作能力方面的重要内容未进行规范:
##单元测试
##实例代码
math.js
exports.add = function() {
var sum = 0, i = 0, args = arguments, l = args.length;
while (i < l) {
sum += args[i++];
}
return sum;
};
increment.js
var add = require('math').add;
exports.increment = function(val) {
return add(val, 1);
};
program.js
var inc = require('increment').increment;
var a = 1;
inc(a); // 2
##依赖闭环解释(译者添加)
因为node.js完全实现了CommonJS Modules/1.0规范,那么我们用其来解释CommonJS Modules/1.0中的依赖闭环问题。看如下代码:
a.js
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,这时候就产生了依赖闭环的问题,为了避免无限循环,需要打破这个闭环。根据CommonJS Modules/1.0规范中的说明「在这种情况下,”require”返回的对象必须至少包含此外部模块在调用require函数(会进入当前模块执行环境)之前就已经准备完毕的输出。」,有些绕,让我们从依赖闭环产生的地方跟踪,b.js需要require a.js,这里b.js做为当前模块,a.js相对于b.js来说是外部模块,那么a.js的输出应该是在其require b.js之前(即「进入当前模块执行环境」)就应该返回,执行过程如下:
a.js
console.log('a starting');
exports.done = false;
// 只执行到这里,然后exports返回给调用模块(b.js),以下被丢弃
var b = require('./b.js');
console.log('in a, b.done = %j', b.done);
exports.done = true;
console.log('a done');
然后b.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
注意,虽然main.js同时require了a.js和b.js,但是根据node.js的模块缓存策略,模块只执行一次。
参考:
http://wiki.commonjs.org/wiki/Modules/1.0
http://nodejs.org/api/modules.html#modules_cycles
(完)