CommonJS
Nodejs的模块系统就采用CommonJS模式。CommonJS标准规定,一个单独的文件就是一个模块,模块内将需要对外暴露的变量放到exports对象里,可以是任意对象,函数,数组等,未放到exports对象里的都是私有的。用require方法加载模块,即读取模块文件获得exports对象。
{
id: '...',
exports: { ... },
loaded: true
}
id是模块名,exports是该模块导出的接口,loaded表示模块是否加载完毕。 以后需要用到这个模块时,就会到exports属性上取值。即使再次执行require命令,也不会再次执行该模块,而是到缓存中取值。
// index.js
exports.add = function(a, b) {
return a + b;
}
// 引入index.js
var math = require('index.js');
math.add(2, 3); // 5
由于CommonJS是同步加载模块,这对于服务器端不是一个问题,因为所有的模块都放在本地硬盘。等待模块时间就是硬盘读取文件时间,很小。但是,对于浏览器而言,它需要从服务器加载模块,涉及到网速,代理等原因,一旦等待时间过长,浏览器处于”假死”状态。
所以在浏览器端,不适合于CommonJS规范。
AMD
CommonJS解决了模块化的问题,但这种同步加载方式并不适合于浏览器端。
AMD(Asynchronous Module Definition)异步加载模块。AMD标准规定,用define来定义模块,用require来加载模块:
这里异步指的是不堵塞浏览器其他任务(dom构建,css渲染等),而加载内部是同步的(加载完模块后立即执行回调)。
AMD采用require命令加载模块,但是不同于CommonJS,它要求两个参数:
require([module], callback);
第一个参数[module],是一个数组,里面的成员是要加载的模块,callback是加载完成后的回调函数。如果将上述的代码改成AMD方式:
require(['math'], function(math) {
math.add(2, 3);
})
其中,回调函数中参数对应数组中的成员(模块)。
具体来说,就是模块书写必须使用特定的define()函数来定义。如果一个模块不依赖其他模块,那么可以直接写在define()函数之中。
define(id?, dependencies?, factory);
- id:模块的名字,如果没有提供该参数,模块的名字应该默认为模块加载器请求的指定脚本的名字
- dependencies:模块的依赖,已被模块定义的模块标识的数组字面量。依赖参数是可选的,如果忽略此参数,它应该默认为 [“require”, “exports”, “module”]。然而,如果工厂方法的长度属性小于3,加载器会选择以函数的长度属性指定的参数个数调用工厂方法。
- factory:模块的工厂函数,模块初始化要执行的函数或对象。如果为函数,它应该只被执行一次。如果是对象,此对象应该为模块的输出值。
例子如下:
// index.js
define(function() {
var add = function(x, y) {
return x + y;
}
return {
add: add
}
})
加载方法如下:
// main.js
require(['index'], function(index) {
alert(index.add(1, 1));
})
如果index模块还依赖其他模块,写法如下:
// index.js
define(['dependenceModule'], function(dependenceModule) {
// ...
})
当require()函数加载math模块的时候,就会先加载dependenceModule模块。当有多个依赖时,就将所有的依赖都写在define()函数第一个参数数组中,所以说AMD是依赖前置的。这不同于CMD规范,它是依赖就近的。
CMD
CMD推崇依赖就近,延迟执行。可以把你的依赖写进代码的任意一行,如下:
define(factory)
factory为函数时,表示是模块的构造方法。执行该构造方法,可以得到模块向外提供的接口。factory 方法在执行时,默认会传入三个参数:require、exports 和 module。
define(function(require,exports,module) {
var a = require('./a');
a.doSomething();
var b = require('./b');
b.doSomething();
})
如果使用AMD写法,如下:
// AMD
define(['a', 'b'], function(a, b) {
a.doSomething();
b.doSomething();
})