在比较以前,咱们得先来了解下什么是AMD规范?什么是CMD规范?固然先申明一下,我我的也是总结下而已,也是网上看到的资料,本身总结下或者能够说整理下而已,供你们更深刻的了解!由于咱们都知道 AMD规范:是 RequireJS 在推广过程当中对模块定义的规范化产出的,而CMD规范:是SeaJS 在推广过程当中对模块定义的规范化产出的。javascript
在CMD中 一个模块就是一个文件,以下代码所示:前端
//基本格式如:define(id, deps, factory) // 好比以下代码 define('hello',['jQuery'],function(require, exports, module) { // 模块代码 });define是一个全局函数,主要是用来定于模块的。其中如上'hello'就是模块名称,['jquery']是依赖项, 也能够依赖于多项能够以下写法['jquery','',''],分别用逗号隔开, 其中上面的id(模块名称)和deps(被依赖项) 是能够省略的。省略时,那么模块名称就是文件名称。 好比我有个文件叫a.js,那么我定义模块时候以下代码所示:define(function(require, exports, module) { // 模块代码 })那么若是我想在b.js代码里面要依赖于a.js的话,那么我能够直接这样写: define(function(require,exports,module){ var a = require('a') }); 可是注意:带有id 和 deps 是不属于CMD规范的。因此在seaJS里面 通常的写法是不带模块名称和依赖项的。 就是如上的代码格式。 下面看看 factory 在seajs里面 factory既能够是函数,对象或者字符串。factory为对象 字符串时候, 表示该模块的接口就是该对象或者字符串,以下能够定义一个json对象。 define({"aa":'bb'}); 和jsonp格式相似,不过这样的数据对象是高度可用的,并且由于是静态对象,他也是CDN友好的,能够提升性能 ,好比说咱们 有个省市区这么一个jSON格式要返回咱们前端,若是以传统JSONP的形式提供给客户端, 它必须提供一个callback函数名,根据这个函数名动态生成返回数据,这使得标准JSONP数据必定不是CDN友好的。 那么咱们能够利用这种格式define({ provinces:[ { name: '上海', areas: ['浦东新区', '徐汇区']}, { name: '江苏', cities: ['南京', '南通']} //..... ]});假设这个文件名为china.js,那么若是某个模块须要这个数据,只须要: define(function(require,exports,module){ var china = require('./china'); //在这里使用中国省市数据 }); 当factory为函数时,表示该模块的构造方法,执行该构造方法,能够获得模块向外提供的接口。 默认会传入三个参数require,exports,module.那么咱们先来看看require参数吧require是一个方法,他能够解决依赖,用于获取其余模块提供的接口,好比下面的a.js代码以下
define(function(require, exports) { exports.a = function(){ // 不少代码 }; });那么如今我想在b.js里面调用a.js里面的a方法。咱们能够以下作:java
define(function(require,exports){ var fun = require('./a'); console.log(fun.a()); // 就能够调用到及执行a函数了。 })require.async(id,callback) : require.async: 方法用来在模块内部异步加载模块,
并在加载完成后执行指定回调。callback参数可选。好比以下代码:define(function(require, exports, module) { // 异步加载一个模块,在加载完成时,执行回调 require.async('./b', function(b) { b.doSomething(); }); // 异步加载多个模块,在加载完成时,执行回调 require.async(['./c', './d'], function(c, d) { c.doSomething(); d.doSomething(); }); });注意: require是同步往下执行的,而require.async 则是异步回调执行。使用模块系统内部的路径解析机制来解析并返回模块路径。该函数不会加载模块,只返回解析后的绝对路径。 define(function(require, exports) { console.log(require.resolve('./b')); // ==> http://example.com/path/to/b.js });exports:是一个对象,用来向外提供模块接口。
好比仍是上面的代码:以下a.js里面define(function(require, exports) { exports.a = function(){ // 不少代码 }; }); //或者以下书写: define(function(require, exports) { return { i: 'a', a: function(){ // 执行相应的代码 } } });那么若是我在b.js里面想要调用a.js里面的a方法,因为a.js使用exports对外提供了接口a方法,那么在b.js里面 咱们只须要先这样 var fun = require('./a');而后执行fun.a();就能够执行a方法了。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 }); //等等属性 具体能够看seajs官网。原理是同样的 由于seajs也采用的是CMD规范。
以下官网代码: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方法。例子中是简单调用了模块beta的verb方法。jquery
其中上面的模块名称和依赖项 也能够省略,那么若是省略的话,那么咱们能够称他们为匿名函数,那么一样 模块名称就是文件名称 和上面的CMD规范相似。上面的['',''] 参数表明了一组对所定义的模块来讲必须的依赖项。第三个参数('definition function')是一个用来为你的模块执行初始化的函数。一个最简单的模块能够以以下方式定义:json
// 模块定义函数 // 依赖项(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 文件中或需要动态读取依赖时加载代码。用法的一个实例以下:api
// 假设 '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 }; });
define(function(require,exports,module){ var a = require('./a'); a.doSomthing(); });
代码在运行时,首先是不知道依赖的,须要遍历全部的require关键字,找出后面的依赖。具体作法是将function toString后,用正则匹配出require关键字后面的依赖。dom
而AMD依赖前置:以下代码:异步
define(['./a','./b'],function(a,b){ //...... a.doSomthing(); //...... b.doSomthing(); })
代码在一旦运行到此处,能当即知晓依赖。而无需遍历整个函数体找到它的依赖,所以性能有所提高,缺点就是开发者必须显式得指明依赖——这会使得开发工做量变大,好比:当依赖项有n个时候 那么写起来比较烦 且容易出错。不过 RequireJS 从 2.0 开始,也改为能够延迟执行(根据写法不一样,处理方式不一样)。async
CMD是延迟执行的,而AMD是提早执行的。函数
AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。好比 AMD 里,require 分全局 require 和局部 require,都叫 require。CMD 里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use 来实现模块系统的加载启动。CMD 里,每一个 API 都简单纯粹。