AMD & CMD & CommonJS

207 阅读4分钟

AMD&CMD&CommonJS

AMD: Asynchronous Modules Definition异步模块定义, 提供定义模块及异步加载该模块依赖的机制,是RequireJS在推广过程中对模块定义的规范化产出 CMD: Common Module Definition 通用模块定义, 提供模块定义及按需执行模块,是SeaJS在推广过程中对模块定义的规范化产出

RequireJS 遵循 AMD(异步模块定义)规范,Sea.js 遵循 CMD (通用模块定义)规范。规范的不同,导致了两者 API 不同。

AMD

AMD规范其实只有一个主要接口 define(id,dependencies,factory),它要在声明模块的时候指定所有的依赖dependencies,并且还要当做形参传到factory中,对于依赖的模块提前执行,依赖前置

define("module", ["dep1", "dep2"], function(d1, d2) {
return someExportedValue;
});
require(["module", "../file"], function(module, file) { /* ... */ });
优点: 适合在浏览器环境异步加载并行加载多个模块 缺点: 提高开发成本,代码阅读和书写比较困难不符合通用的模块思维方式,是一种妥协的实现

CMD

在CMD中一个模块就是一个文件 CMD规范和AMD相似,尽量保持简单,并且与CommonJS和NodeJS的Modules规范保持了很大的兼容性。

//基本格式如:define(id, deps, factory) // 比如如下代码 define('hello',['jQuery'],function(require, exports, module) { // 模块代码 }); define(function(require, exports, module) {
var a = require("./a"); //等待a.js下载、执行完
a.doing(); // 此处省略500行代码
var b = require("./b"); //依赖就近书写 b.doing(); }); define是一个全局函数,主要是用来定义模块的。其中如上'hello'就是模块名称,['jquery']是依赖项,也可以依赖于多项可以如下写法['jquery','',''],分别用逗号隔开,其中上面的id(模块名称)和deps(被依赖项) 是可以省略的。省略时,那么模块名称就是文件名称。比如我有个文件叫a.js,那么我定义模块时候如下代码所示:

那么如果我想在b.js代码里面要依赖于a.js的话,那么我可以直接这样写:

define(function(require,exports,module){ var a = require('a') }); 优点: 依赖就近,延迟执行很容易在node中运行 缺点: 依赖SPM打包,模块的加载逻辑偏重 注意:带有id 和 deps 是不属于CMD规范的。所以在seaJS里面 一般的写法是不带模块名称和依赖项的。就是如上的代码格式。

CommonJS

这种方式通过一个叫做require的方法,同步加载依赖,然后返导出API供其它模块使用,一个模块可以通过exports或者module.exports导出API。CommonJS规范中,一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,在一个文件中定义的变量,都是私有的,对其他文件是不可见的。 Well 服务端模块可以很好的复用 这种风格的模块已经很多了,比如npm上基本上都是这种风格的module 简单易用 Less Well 加载模块是同步的,所以只有加载完成才能执行后面的操作 多个模块不能并行加载 像Node.js主要用于服务器的编程,加载的模块文件一般都已经存在本地硬盘,所以加载起来比较快,不用考虑异步加载的方式,所以CommonJS规范比较适用。但如果是浏览器环境,要从服务器加载模块,这是就必须采用异步模式。所以就有了 AMD 、CMD 的解决方案。 CommonJS规范 CommonJS是在浏览器环境之外构建JavaScript生态系统为目标产生的项目,比如服务器和桌面环境中。CommonJS规范是为了解决JavaScript的作用域问题而定义的模块形式, 可以使每个模块在它自身的命名空间中执行。该规范的主要内容是:模块必须通过 module.exports导出对外的变量或接口,通过require()来导入其他模块的输出到当前模块。 例子:

// moduleA.js module.exports = function () { return value * 2 } // moduleB.js var multiplyby2 = require('./moduleA') var result = multiplyby2(4) CommonJS是同步加载模块,但其实也有浏览器端的实现,其原理是将所有模块都定义好并通过id进行索引,这样就可以浏览器进行解析了 服务器端的Node.js遵循CommonJS规范。核心思想是允许模块通过require 方法来同步加载所要依赖的其他模块,然后通过 exports或module.exports来导出需要暴露的接口。

优点: 服务器端便于重用NPM中已经将近20w个模块包简单并容易使用缺点:

同步的模块方式不适合不适合在浏览器环境中,同步意味着阻塞加载,浏览器资源是异步加载的不能非阻塞的并行加载多个模块