CMD与AMD比较

这篇文章主要介绍了SeaJS 与 RequireJS 的差异对比,本文主要对CMD规范和AMD规范的弊端做了对比,并做出了一个总结,需要的朋友可以参考下

“历史不是过去,历史正在上演。随着 W3C 等规范、以及浏览器的飞速发展,前端的模块化开发会逐步成为基础设施。一切终究都会成为历史,未来会更好。”——引用玉伯原文最后一段话,我个人也非常赞同。既然谈到了“未来”,我个人认为:前端 js 模块如果继续发展,其模块格式很可能会成为未来 WEB 一种标准规范,产生多种实现方式。就好比 JSON 格式一样,最终成为标准、被浏览器原生实现。

谁更有能成为未来的异步模块标准?SeaJS 遵循 CMD 规范,RequireJS 遵循 AMD 规范,先从这两种不同的格式说起。

CMD

CMD 模块依赖声明方式:

代码如下:
define(function (require) {
    var a = require('./a');
    var b = require('./b');
    // more code ..
})

CMD 依赖是就近声明,通过内部require方法进行声明。但是因为是异步模块,加载器需要提前加载这些模块,所以模块真正使用前需要提取模块里面所有的依赖。无论是加载器即时提取,还是通过自动化工具预先提取,CMD 的这种依赖声明格式只能通过静态分析方式实现,这也正是 CMD 的弊端所在。

CMD 规范的弊端

不能直接压缩:require是局部变量,意味着不能直接的通过压缩工具进行压缩,若require这个变量被替换,加载器与自动化工具将无法获取模块的依赖。
模块书写有额外约定:路径参数不能进行字符串运算,不能使用变量代替,否则加载器与自动化工具无法正确提取路径。
规范之外的约定意味着更多的文档说明,除非它们也是规范中的一部分。

注:SeaJS 静态分析实现是把模块包toString()后使用正则提取require部分得到依赖的模块路径。

AMD

AMD 模块依赖声明方式:

 代码如下:
define(['./a', './b'], function (a, b) {
    // more code ..
})

AMD 的依赖是提前声明。这种优势的好处就是依赖无需通过静态分析,无论是加载器还是自动化工具都可以很直接的获取到依赖,规范的定义可以更简单,意味着可能产生更强大的实现,这对加载器与自动化分析工具都是有利的。

AMD 规范的弊端

依赖提前声明在代码书写上不是那么友好。
模块内部与 NodeJS 的 Modules 有一定的差异。
关于第二点的问题需要特别说明下。其实无论是 CMD 还是 AMD 的异步模块,都无法与同步模块规范保持一致(NodeJS 的 Modules),只有谁比谁更像同步模块而已。AMD 要转换为同步模块,除了去掉define函数的包裹外,需要在头部使用require把依赖声明好,而 CMD 只需要去掉define函数的包裹即可。

总结

从规范上来说,AMD 更加简单且严谨,适用性更广,而在 RequireJS 强力的推动下,在国外几乎成了事实上的异步模块标准,各大类库也相继支持 AMD 规范。

但从 SeaJS 与 CMD 来说,也做了很多不错东西:

1、相对自然的依赖声明风格
2、小而美的内部实现
3、贴心的外围功能设计
4、更好的中文社区支持



本篇文章给大家介绍js模块规范之AMD规范和CMD规范,模块化是一种处理复杂系统分解为代码结构更合理,可维护性更高的可管理的模块的方式,对js amd cmd规范感兴趣的童鞋可以来本文学习

模块化是指在解决某一个复杂问题或者一系列的杂糅问题时,依照一种分类的思维把问题进行系统性的分解以之处理。模块化是一种处理复杂系统分解为代码结构更合理,可维护性更高的可管理的模块的方式。可以想象一个巨大的系统代码,被整合优化分割成逻辑性很强的模块时,对于软件是一种何等意义的存在。对于软件行业来说:解耦软件系统的复杂性,使得不管多么大的系统,也可以将管理,开发,维护变得“有理可循”。

还有一些对于模块化一些专业的定义为:模块化是软件系统的属性,这个系统被分解为一组高内聚,低耦合的模块。那么在理想状态下我们只需要完成自己部分的核心业务逻辑代码,其他方面的依赖可以通过直接加载被人已经写好模块进行使用即可。

一、AMD

AMD就只有一个接口:define(id?,dependencies?,factory);

它要在声明模块的时候制定所有的依赖(dep),并且还要当做形参传到factory中,像这样:

复制代码 代码如下:

define(['dep1','dep2'],function(dep1,dep2){...});

要是没什么依赖,就定义简单的模块,下面这样就可以啦

?
1
2
3
4
5
define( function (){
   var exports = {};
   exports.method = function (){...};
   return exports;
});

这里有define,把东西包装起来,那Node实现中怎么没看到有define关键字呢,它也要把东西包装起来,其实,只是Node隐式包装了而已..

RequireJS就是实现了AMD规范的

二、CMD

玉伯写了seajs,就是遵循他提出的CMD规范,比AMD稍微强大点,用起来感觉也方便些

三、AMD与CMD的区别

CMD相当于按需加载,定义一个模块的时候不需要立即制定依赖模块,在需要的时候require就可以了,比较方便;而AMD则相反,定义模块的时候需要制定依赖模块,并以形参的方式引入factory中

//AMD方式定义模块

?
1
2
3
4
define([ 'dep1' , 'dep2' ], function (dep1,dep2){
   //内部只能使用制定的模块
   return function (){};
});

//CMD

?
1
2
3
4
define( function (require,exports,module){
  //此处如果需要某XX模块,可以引入
  var xx=require( 'XX' );
});

而SEAJS也有use功能也是需要先引入所有依赖的模块,如

?
1
2
3
4
//SEAJS.Use方式
seajs.use([ 'dep1' , 'dep2' ], function (dep1,dep2){
   //这里实现事务
});

 四、插件支持

但全球有两种比较流行的 JavaScript 模块化体系,一个是 Node 实现的 CommonJS,另外一个是 AMD。很多类库都同时支持 AMD 和 CommonJS,但是不支持 CMD。或许国内有很多 CMD 模块,但并没有在世界上流行起来。

现在比较火的 React 及周边类库,就是直接使用 CommonJS 的模块体系,使用 npm 管理模块,使用 Browserify 打包输出模块。
不久的将来 ES6 中新的模块化标准,可能就都得遵循新的标准了,什么AMD、CMD可能到时也不会怎么用了。

但是目前来说,前端开发没有用模块化编程就真的out的了,而目前的模块化编程,本人还是建议用SEAJS,虽然很多插件需要追加或修改一小块代码才能支持。但改过一次就能反复使用,也不会影响其它标准的支持。总体还算是比较方便实用的。

单独解释AMD 与 CMD 区别到底在哪里?

    看了以上 AMD,requireJS 与 CMD, seaJS的简单介绍会有点感觉模糊,总感觉较为相似。因为像 requireJS 其并不是只是纯粹的AMD固有思想,其也是有CMD规范的思想,只不过是推荐 AMD规范方式而已, seaJS也是一样。

    下面是玉伯对于 AMD 与 CMD 区别的解释:

    AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。

    CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。

    类似的还有 CommonJS Modules/2.0 规范,是 BravoJS 在推广过程中对模块定义的规范化产出还有不少??

    这些规范的目的都是为了 JavaScript 的模块化开发,特别是在浏览器端的。 

   目前这些规范的实现都能达成浏览器端模块化开发的目的。    

 区别:

    1. 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.

    2. CMD 推崇依赖就近,AMD 推崇依赖前置。看代码:

// CMD

?
1
2
3
4
5
6
7
8
define( function (require, exports, module) {
  var a = require( './a' )
  a.doSomething()
  // 此处略去 100 行
  var b = require( './b' ) // 依赖可以就近书写
  b.doSomething()
  // ...
})

// AMD 默认推荐的是

1
2
3
4
5
6
define([ './a' , './b' ], function (a, b) { // 依赖必须一开始就写好
  a.doSomething()
  // 此处略去 100 行
  b.doSomething()
  // ...
})

虽然 AMD 也支持 CMD 的写法,同时还支持将 require 作为依赖项传递,但 RequireJS 的作者默认是最喜欢上面的写法,也是官方文档里默认的模块定义写法。

    3. AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。比如 AMD 里,require 分全局 require 和局部 require,都叫 require。CMD 里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use 来实现模块系统的加载启动。

CMD 里,每个 API 都简单纯粹。

    4. 还有一些细节差异,具体看这个规范的定义就好,就不多说了。

相关文章
相关标签/搜索