CMD
CMD规范:是SeaJS 在推广过程中对模块定义的规范化产出的。
什么是CMD规范:
在CMD中,一个模块就是一个文件
define(function(require,exports,module){
//模块代码
})
define是一个全局函数,主要用来定义模块。
将上述代码保存在文件acot.js中,那么我想要在bcont.js中依赖于acont.js的话,可以:
define(function(require,exports,module){
var require('acont.js');
})
在seaJS中 factory可以是函数、对象或者字符串。factory为对象 字符串时候,表示该模块的接口就是该对象或者字符串
define({
provinces: [
{
name: '上海',
areas: ['浦东新区', '徐汇区']},
{
name: '江苏',
cities: ['南京', '南通']}
//.....
]
});
假设这个文件名为json.js,那么如果某个模块需要这个数据,只需要:
define(function(require,exports,module){
var china = require('./json');
//在这里使用中国省市数据
});
-
当factory为函数时,表示该模块的构造方法,执行该构造方法,可以得到模块向外提供的接口。默认会传入三个参数require,exports,module
- 是一个方法,他可以解决依赖,用于获取其他模块提供的接口
/*acont.js中的代码:*/
define(function(require, exports) {
exports.a = function(){
// 很多代码
};
});
在bcont.js里面调用acont.js里面的a方法
define(function(require,exports){
var fun = require('./acont');
console.log(fun.a()); // 就可以调用到及执行a函数了。
})
-
require.async: 方法用来在模块内部异步加载模块,并在加载完成后执行指定回调。callback参数可选
require.async(id,callback) :
define(function(require, exports, module) {
// 异步加载一个模块,在加载完成时,执行回调
require.async('./bcont', function(b) {
b.doSomething();
});
// 异步加载多个模块,在加载完成时,执行回调
require.async(['./ccont', './dcont'], function(c, d) {
c.doSomething();
d.doSomething();
});
});
/*require是同步往下执行的,而require.async 则是异步回调执行*/
-
使用模块系统内部的路径解析机制来解析并返回模块路径。该函数不会加载模块,只返回解析后的绝对路径。
require.resolve(id)
define(function(require, exports) {
console.log(require.resolve('./bcont'));
// ==> http://example.com/path/to/bcont.js
});
exports:是一个对象,用来向外提供模块接口
define(function(require, exports) {
exports.a = function(){
// 很多代码
};
});
define(function(require, exports) {
return {
i: 'a',
a: function(){
// 执行相应的代码
}
}
});
module
module 是一个对象,上面存储了与当前模块相关联的一些属性和方法。其中exports是module.exports的一个引用。
moudle.id 模块的唯一标识
define('id', [], function(require, exports, module) {
// 模块代码
});
module.uri 根据模块系统的路径解析规则得到的模块绝对路径
define(function(require, exports, module) {
console.log(module.uri);
// ==> http://example.com/path/to/this/file.js
});
AMD 规范
define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {
exports.verb = function() {
return beta.verb();
//或者:
return require("beta").verb();
}
});
require函数让你能够随时去依赖一个模块,即取得模块的引用,从而即使模块没有作为参数定义,也能够被使用;exports是定义的 alpha 模块的实体,在其上定义的任何属性和方法也就是alpha模块的属性和方法。通过exports.verb = …就是为alpha模块定义了一个verb方法,第三个参数(’definition function’)是一个用来为你的模块执行初始化的函数
// 模块定义函数
// 依赖项(foo 和 bar)被映射为函数的参数
define('myMoudle',['foo','bar'],function(foo,bar){
// 返回一个定义了模块导出接口的值
// (也就是我们想要导出后进行调用的功能)
// 在这里创建模块
var myModule = {
doStuff:function(){
console.log('Yay! Stuff');
}
}
return myModule;
});
define('myModule',['math', 'graph'], function ( math, graph ) {
// 请注意这是一个和 AMD 有些许不同的模式,但用几种不同的方式
// 来定义模块也是可以的,因为语法在某些方面还是比较灵活的
return {
plot: function(x, y){
return graph.drawPie(math.randomGrid(x,y));
}
}
};
});
require 则主要用来在顶层 JavaScript 文件中或须要动态读取依赖时加载代码
// 假设 'foo' 和 'bar' 是两个外部模块
// 在本例中,这两个模块被加载后的 'exports' 被当做两个参数传递到了回调函数中
// 所以可以像这样来访问他们
require(['foo', 'bar'], function ( foo, bar ) {
// 这里写其余的代码
foo.doSomething();
});
define(function ( require ) {
var isReady = false,
foobar;
// 请注意在模块定义内部内联的 require 语句
require(['foo', 'bar'], function (foo, bar) {
isReady = true;
foobar = foo() + bar();
});
// 我们仍可以返回一个模块
return {
isReady: isReady,
foobar: foobar
};
});
CMD规范与AMD规范的区别如下
- CMD依赖就近
define(function(require,exports,module){
var a = require('./a');
a.doSomthing();
});
AMD依赖前置
define(['./a','./b'],function(a,b){
//......
a.doSomthing();
//......
b.doSomthing();
})
无需遍历整个函数体找到它的依赖,因此性能有所提升,缺点就是开发者必须显式得指明依赖——这会使得开发工作量变大
CMD是延迟执行的,而AMD是提前执行的
/*ADM加载器*/
define("path/library-name", [
"require",
"jquery",
"./relative-path/library",
"absolute-path/library"
], function f(require, $, lib, anotherLib) {
// do something
// and return the module itself.
});
/*
@脚本文件被加载时, AMD 的 define 函数被执行。它会用一些预定义的规则解析依赖路径,并且把未载入也未进入等待列表的依赖放入等待列表,并加载这些依赖所对应的文件
@当所有依赖被加载和执行完成后,执行传入的回调函数 (在此被记为 f) 才被执行,而此时加载器提供的回调函数把返回值填充于一个内部的哈希表里,以这里指定的模块名称 path/library-name, 或者隐式的使用当前加载的文件名作为模块名称为键
@相对我们定义模块的函数 f, AMD 加载器是提前执行所有依赖
*/
/*
@ CMD 加载器
@ 与 AMD 不同的是, CMD 加载器在依赖分析阶段通过字符串分析函数内形如 require("stringLiteral") 的正则匹配来获取所有依赖项。
@ 通过回调函数的Function.toString函数,使用正则表达式来捕捉内部的require字段,找到require('jquery')内部依赖的模块jquery
@ 根据配置文件,找到jquery的js文件的实际路径
@ 在dom中插入script标签,载入模块指定的js,绑定加载完成的事件,使得加载完成后将js文件绑定到require模块指定的id(这里就是jquery这个字符串)上
@ 回调函数内部依赖的js全部加载(暂不调用)完后,调用回调函数
@ 当回调函数调用require('jquery'),即执行绑定在'jquery'这个id上的js文件
*/
api设计
AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。比如 AMD 里,require 分全局 require 和局部 require,都叫 require。CMD 里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use 来实现模块系统的加载启动。CMD 里,每个 API 都简单纯粹