1.名词解释
AMD:Asynchronous Modules Definition异步模块定义,提供定义模块及异步加载该模块依赖的机制。
CMD:Common Module Definition 通用模块定义,提供模块定义及按需执行模块

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

2. 提前执行:提前异步并行加载
优点:尽早执行依赖可以尽早发现错误;缺点:容易产生浪费
3. 延迟执行:延迟按需加载
优点:减少资源浪费 缺点:等待时间长、出错时间延后

2.1 AMD与CMD代码模式

AMD代码模式-运行策略

define(['./a', './b'], function(a, b) { //运行至此,a.js和b.js已经下载完成 a模块和b模块已经执行完,直接可用;
    a.doing();// 此处省略500行代码
    b.doing();
});

CMD代码模式-运行策略

define(function(require, exports, module) {var a = require("./a"); //等待a.js下载、执行完
     a.doing();// 此处省略500行代码var b = require("./b"); //依赖就近书写
     b.doing();
});

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

方案 | 优势 | 劣势 | 特点
AMD | 速度快 | 会浪费资源 | 预先加载所有的依赖,直到使用的时候才执行
CMD | 只有真正需要才加载依赖 | 性能较差 | 直到使用的时候才定义依赖

它们除了希望放在浏览器作为loader也能够放在服务端,提供加载功能。在我看来,AMD擅长在浏览器端、CMD擅长在服务器端。这是因为浏览器加载一个功能不像服务器那么快,有大量的网络消耗。所以一个异步loader是更接地气的。

或者,干脆使用YUI3的模块机制,在上线前进行压制。把互相依赖的模块压在一个文件中。

---------------------------------------------------------------------------------------------------

每一个卓越的思想都有一份朴实的代码实现。所以无论AMD与CMD都要面临以下几个问题:

1、模块式如何注册的,define函数都做了什么?
2、他们是如何知道模块的依赖?
3、如何做到异步加载?尤其是seajs如何做到异步加载延迟执行的?
辩证法第一规律:事物之间具有有机联系。AMD与CMD都借鉴了CommonJs,宏观层面必有一致性,比如整体处理流程:
模块的加载解析到执行过程一共经历了6个步骤:
1、由入口进入程序
2、进入程序后首先要做的就是建立一个模块仓库(这是防止重复加载模块的关键),JavaScript原生的object对象最为适合,key代表模块Id,value代表各个模块,处理主模块
3、向模块仓库注册一模块,一个模块最少包含四个属性:id(唯一标识符)、deps(依赖项的id数组)、factory(模块自身代码)、status(模块的状态:未加载、已加载未执行、已执行等),放到代码中当然还是object最合适
4、模块即是JavaScript文件,使用无阻塞方式(动态创建script标签)加载模块

scriptElement= document.createElement('script');
scriptElement.src = moduleUrl;
scriptElement.async = true;
scriptElement.onload = function(){.........};
document.head.appendChild(scriptElement);

  5、模块加载完毕后,获取依赖项(amd、cmd区别),改变模块status,由statuschange后,检测所有模块的依赖项。

  由于requirejs与seajs遵循规范不同,requirejs在define函数中可以很容易获得当前模块依赖项。而seajs中不需要依赖声明,所以必须做一些特殊处理才能否获得依赖项。方法将factory作toString处理,然后用正则匹配出其中的依赖项,比如出现require(./a),则检测到需要依赖a模块。

  同时满足非阻塞和顺序执行就需要需要对代码进行一些预处理,这是由于CMD规范和浏览器环境特点所决定的。

  6、如果模块的依赖项完全加载完毕(amd中需要执行完毕,cmd中只需要文件加载完毕,注意这时候的factory尚未执行,当使用require请求该模块时,factory才会执行,所以在性能上seajs逊于requirejs),执行主模块的factory函数;否则进入步骤3.

AMD规范定义了一个自由变量或者说是全局变量 define 的函数

define( id?, dependencies?, factory );

第一个参数 id 为字符串类型,表示了模块标识,为可选参数。若不存在则模块标识应该默认定义为在加载器中被请求脚本的标识。如果存在,那么模块标识必须为顶层的或者一个绝对的标识。
第二个参数,dependencies ,是一个当前模块依赖的,已被模块定义的模块标识的数组字面量。
第三个参数,factory,是一个需要进行实例化的函数或者一个对象。
创建模块标识为 alpha 的模块,依赖于 require, export,和标识为 beta 的模块  
  1. define("alpha", [ "require", "exports", "beta" ], function( require, exports, beta ){
  2. export.verb = function(){
  3. return beta.verb();
  4. // or:
  5. return require("beta").verb();
  6. }
  7. });
一个返回对象字面量的异步模块
  1. define(["alpha"], function( alpha ){
  2. return {
  3. verb : function(){
  4. return alpha.verb() + 1 ;
  5. }
  6. }
  7. });
无依赖模块可以直接使用对象字面量来定义
  1. define( {
  2. add : function( x, y ){
  3. return x + y ;
  4. }
  5. } );
require();
在 AMD 规范中的 require 函数与一般的 CommonJS中的 require 不同。由于动态检测依赖关系使加载异步,对于基于回调的 require 需求强烈。

局部 与 全局 的require

局部的 require 需要在AMD模式中的 define 工厂函数中传入 require。
  1. define( ['require'], function( require ){
  2. // ...
  3. } );
  4. or:
  5. define( function( require, exports, module ){
  6. // ...
  7. } );
局部的 require 需要其他特定的 API 来实现。
全局的 require 函数是唯一全局作用域下的变量,像 define一样。全局的 require 并不是规范要求的,但是如果实现全局的 require函数,那么其需要具有与局部 require 函数 一样的以下的限定:
1. 模块标识视为绝对的,而不是相对的对应另一个模块标识。
2. 只有在异步情况下,require的回调方式才被用来作为交互操作使用。因为他不可能在同步的情况下通过 require(String) 从顶层加载模块。
依赖相关的API会开始模块加载。如果需要有互操作的多个加载器,那么全局的 reqiure 应该被加载顶层模块来代替。
  1. require(String)
  2. define( function( require ){
  3. var a = require('a'); // 加载模块a
  4. } );
  5. require(Array, Function)
  6. define( function( require ){
  7. require( ['a', 'b'], function( a,b ){ // 加载模块a b 使用
  8. // 依赖 a b 模块的运行代码
  9. } );
  10. } );
  11. require.toUrl( Url )
  12. define( function( require ){
  13. var temp = require.toUrl('./temp/a.html'); // 加载页面
  14. } );

define 和 require 这两个定义模块,调用模块的方法合称为AMD模式,定义模块清晰,不会污染全局变量,清楚的显示依赖关系。AMD模式可以用于浏览器环境并且允许非同步加载模块,也可以按需动态加载模块。
在CMD中,一个模块就是一个文件,格式为:
define( factory );
全局函数define,用来定义模块。
参数 factory  可以是一个函数,也可以为对象或者字符串。
当 factory 为对象、字符串时,表示模块的接口就是该对象、字符串。
定义JSON数据模块:
  1. define({ "foo": "bar" });
通过字符串定义模板模块:
  1. define('this is {{data}}.');
factory 为函数的时候,表示模块的构造方法,执行构造方法便可以得到模块向外提供的接口。
  1. define( function(require, exports, module) {
  2. // 模块代码
  3. });
define( id?, deps?, factory );
define也可以接受两个以上的参数,字符串id为模块标识,数组deps为模块依赖:
  1. define( 'module', ['module1', 'module2'], function( require, exports, module ){
  2. // 模块代码
  3. } );
其与 AMD 规范用法不同。

require 是 factory 的第一个参数。
require( id );
接受模块标识作为唯一的参数,用来获取其他模块提供的接口:
  1. define(function( require, exports ){
  2. var a = require('./a');
  3. a.doSomething();
  4. });
require.async( id, callback? );
require是同步往下执行的,需要的异步加载模块可以使用 require.async 来进行加载:
  1. define( function(require, exports, module) {
  2. require.async('.a', function(a){
  3. a.doSomething();
  4. });
  5. });
require.resolve( id )
可以使用模块内部的路径机制来返回模块路径,不会加载模块。
exports 是 factory 的第二个参数,用来向外提供模块接口。
  1. define(function( require, exports ){
  2. exports.foo = 'bar'; // 向外提供的属性
  3. exports.do = function(){}; // 向外提供的方法
  4. });
当然也可以使用 return 直接向外提供接口。
  1. define(function( require, exports ){
  2. return{
  3. foo : 'bar', // 向外提供的属性
  4. do : function(){} // 向外提供的方法
  5. }
  6. });
也可以简化为直接对象字面量的形式:
  1. define({
  2. foo : 'bar', // 向外提供的属性
  3. do : function(){} // 向外提供的方法
  4. });
与nodeJS中一样需要注意的是,一下方式是错误的:
  1. define(function( require, exports ){
  2. exports = {
  3. foo : 'bar', // 向外提供的属性
  4. do : function(){} // 向外提供的方法
  5. }
  6. });
需要这么做
  1. define(function( require, exports, module ){
  2. module.exports = {
  3. foo : 'bar', // 向外提供的属性
  4. do : function(){} // 向外提供的方法
  5. }
  6. });
传入的对象引用可以添加属性,一旦赋值一个新的对象,那么之前传递进来的对象引用就会失效了。开始之初,exports 是作为 module.exports 的一个引用存在,一切行为只有在这个引用上 factory 才得以正常运行,赋值新的对象后就会断开引用,exports就只是一个新的对象引用,对于factory来说毫无意义,就会出错。
module 是factory的第三个参数,为一个对象,上面存储了一些与当前模块相关联的属性与方法。
module.id 为模块的唯一标识。
module.uri 根据模块系统的路径解析规则得到模块的绝对路径。
module.dependencies 表示模块的依赖。
module.exports 当前模块对外提供的接口。
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()来导入其他模块的输出到当前模块。
例子:
[javascript] view plain copy  
  1. // moduleA.js
  2. module.exports = function( value ){
  3. return value * 2;
  4. }
[javascript] view plain copy  
  1. // moduleB.js
  2. var multiplyBy2 = require('./moduleA');
  3. var result = multiplyBy2(4);

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

[javascript] view plain copy  
  1. require("module");
  2. require("../file.js");
  3. exports.doStuff = function() {};
  4. module.exports = someValue;
优点:
  • 服务器端便于重用
  • NPM中已经将近20w个模块包
  • 简单并容易使用
缺点:

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

AMD

AMD规范其实只有一个主要接口 define(id,dependencies,factory),它要在声明模块的时候指定所有的依赖dependencies,并且还要当做形参传到factory中,对于依赖的模块提前执行,依赖前置
[javascript] view plain copy  
  1. define("module", ["dep1", "dep2"], function(d1, d2) {
  2. return someExportedValue;
  3. });
  4. require(["module", "../file"], function(module, file) { /* ... */ });

优点:

  • 适合在浏览器环境异步加载
  • 并行加载多个模块
缺点:
  • 提高开发成本,代码阅读和书写比较困难
  • 不符合通用的模块思维方式,是一种妥协的实现

CMD

CMD规范和AMD相似,尽量保持简单,并且与CommonJS和NodeJS的Modules规范保持了很大的兼容性。

[javascript] view plain copy  
  1. define(function(require, exports, module) {
  2. var $ = require('jquery');
  3. var Spinning = require('./spinning');
  4. exports.doSomething = ...
  5. module.exports = ...
  6. })

优点:

  • 依赖就近,延迟执行
  • 很容易在node中运行
缺点:

  • 依赖SPM打包,模块的加载逻辑偏重

转载于:https://www.cnblogs.com/gopark/p/10142060.html

AMD、CMD和Common规范相关推荐

  1. 关于 CommonJS AMD CMD UMD 规范的差异总结

    根据CommonJS规范,一个单独的文件就是一个模块.每一个模块都是一个单独的作用域,也就是说,在一个文件定义的变量(还包括函数和类),都是私有的,对其他文件是不可见的. // foo.js var ...

  2. 理解AMD ,CMD,CommonJS规范

    https://blog.csdn.net/xcymorningsun/article/details/52709608 理解AMD ,CMD,CommonJS规范 2016年09月30日 10:33 ...

  3. 兼容多种模块规范(AMD,CMD,Node)的代码

    前言 昨天,公司同事问了我如下一个问题: 说他在看一个插件时,看到了源码结构如截图所示,他知道(function(){})()是一种立即执行函数,但是在截图中,最后的那个圆括号里又写了一个函数func ...

  4. JavaSript模块化 AMD CMD 详解.....

    模块化是指在解决某一个复杂问题或者一系列的杂糅问题时,依照一种分类的思维把问题进行系统性的分解以之处理.模块化是一种处理复杂系统分解为代码结构更合理,可维护性更高的可管理的模块的方式.可以想象一个巨大 ...

  5. JS JavaScript模块化(ES Module/CommonJS/AMD/CMD)

    前言 前端开发中,起初只要在script标签中嵌入几十上百行代码就能实现一些基本的交互效果,后来js得到重视,应用也广泛起来了, jQuery,Ajax,Node.Js,MVC,MVVM等的助力也使得 ...

  6. CommonJS,AMD,CMD,ES6,require 和 import 详解

    CommonJS,AMD,CMD,ES6 commonJS用同步的方式加载模块.在服务端,模块文件都存在本地磁盘,读取非常快,所以这样做不会有问题.但是在浏览器端,限于网络原因,更合理的方案是使用异步 ...

  7. commonjs是什么_JavaScript模块化标准CommonJS/AMD/CMD/UMD/ES6Module的区别

    JS-模块化进程 随着js技术的不断发展,途中会遇到各种问题,比如模块化. 那什么是模块化呢,他们的目的是什么? 定义:如何把一段代码封装成一个有用的单元,以及如何注册此模块的能力.输出的值依赖引用: ...

  8. AMD, CMD, CommonJS和UMD

    AMD, CMD, CommonJS和UMD 今天由于项目中引入的echarts的文件太大,requirejs经常加载超时,不得不分开来加载echarts的各个图表.但是使用echarts自带的在线构 ...

  9. 让你的插件兼容AMD, CMD ,CommonJS和 原生 JS

    模块标准 // 支持AMD,CMD以及原生js的引用if (typeof module !== 'undefined' && typeof exports === 'object' & ...

  10. AMD/CMD/CommonJs到底是什么?它们有什么区别?

    这篇文章总结的很好. 知道JS有模块化开发的说法,也偶尔听过requireJs,AMD,CMD等等名字,甚至使用node的时候,还用过require之类的方法,但是对这些一直没有一个明确的认识和概念. ...

最新文章

  1. 2021-2027全球与中国奶牛冻精市场现状及未来发展趋势
  2. 一次Dubbo拥堵的分析
  3. 巨潮网怎么下载年报_上海注册公司后如何下载电子营业执照
  4. python实现秒杀商品的微信自动提醒功能(附代码)
  5. spark学习-55-源代码:SparkSession的的创建
  6. 遍历删除List中的元素,会报错? 用iterator.remove() 完美解决
  7. element 使用阿里图标变形了_2TB不限速的阿里网盘App来了 终于不再忍受众生平等盘...
  8. 锻造完美U盘小偷:活用消息机制
  9. WF4读书笔记(一):创建一个简单的工作流
  10. 7 Python文件和数据格式化
  11. 国家级计算机实验教学师范中心,国家级实验教学示范中心
  12. 大航海懒神辅助工具全部更新完毕,祝大家航海愉快!
  13. 在持续集成 (CI) 环境中使用 Android 模拟器 | AndroidDevSummit 中文字幕视频
  14. 豆瓣评分小程序Part-3
  15. 电路抗干扰设计——非常详细
  16. 孩子握笔姿势错误也易致近视
  17. 基于EasyNVR摄像机流媒体服务器实现RTSP或Onvif监控摄像头Web无插件化直播监控
  18. 卸载WPS后,原office出现各种问题,报错,图标混乱
  19. 攻防世界pwn——forgot
  20. 学计算机要重修一门语言嘛,大学挂科率“最高”的4门科目,不仅要补考还要重修,你中招了吗...

热门文章

  1. Spring Cloud微服务实战:手把手带你整合eurekazuulfeignhystrix(附源码)
  2. vue(2)学习历程----从iview框架入手
  3. Dell™ PowerEdge™ R710机架式服务器旨在成为虚拟化企业的构建块
  4. 微信中location.reload失效
  5. C#开发高亮语法编辑器(一)——TextBox ,RichTextBox的局限性
  6. python 并发编程 多线程 守护线程
  7. socket 关于同一条TCP链接数据包到达顺序的问题
  8. 数据库事务的四大特性以及隔离级别
  9. mac 查看端口的使用情况
  10. ssh图示+hibernate图示