文章目录
  1. 1. CMD 简介
  2. 2. CMD 规范的 API
    1. 2.1. define()
      1. 2.1.1. factory()
        1. 2.1.1.1. 加载模块 require
        2. 2.1.1.2. 提供模块接口
        3. 2.1.1.3. module 对象
    2. 2.2. define.cmd
  3. 3. 小结
  4. 4. 参考

本系列博客更像是读blog读文档的笔记,从诸多资料中梳理出了自己的认识。

JS 的模块化编程(一)- 模块的基本写法
JS 的模块化编程(二)- CommonJS
JS 的模块化编程(三)- AMD
JS 的模块化编程(四)- CMD
JS 的模块化编程(五)- AMD 和 CMD 的区别
JS 的模块化编程(六)- requireJS

CMD 简介

Common Module Definition,CMD
兼容 CommonJS 规范,它与 AMD 有很多相似之处

CMD 规范的 API

define()

define(id?, dependencies?, factory),定义模块

  1. 当 id, dependencies 被省略时,可通过构建工具自动生成
  2. factory 函数|对象|字符串
  • 当是对象|字符串时,模块的接口就是该对象|字符串
  • 当是函数时-模块的构造方法,执行后得到模块的对外接口
    默认三个参数 define(factory(require, exports, module){}),下面依次介绍 factory 的这三个参数

factory()

define(factory(require, exports, module){})

加载模块 require

1.require(id) id 是模块标识,同步加载

1
2
3
4
define(function(require, exports, module){
var a = require('./a'); //加载模块a
a.doSomething(); //使用模块
});

2.require.async(id, callback?) 异步加载

1
2
3
4
5
6
7
define(function(require, exports, module){
//异步加载多个模块,在两个模块都加载完成后,会执行回调
require.async(['./c','./d'], function(c, d){
c.doSomething();
d.doSomething();
});
});

提供模块接口

1.exports 对象,向外提供模块接口

1
2
3
4
5
6
define(function(require, exports, module){
exports.foo = "hello world"; //对外提供的foo属性
exports.add = function(a, b){ //对外提供的add方法
return a+b;
};
});

2.return 直接向外提供接口

1
2
3
4
5
6
7
8
define(function(require, exports, module){
return {
foo: "", //对外提供的foo属性
add: function(a, b){ //对外提供的add方法
return a+b;
}
};
});

module 对象

module.exports, module.id, module.url, module.dependencies,更多详情查看 CMD 模块定义规范

define.cmd

define.cmd 对象
判断页面中是否有 CMD 模块加载器

1
2
3
if(typeof define==="function" && define.cmd){
//有CMD模块加载器存在,eg. sea.js
}

小结

CMD 对模块是按需加载的。它与 AMD(对依赖的模块是提前预加载的)的区别,我们来看下面的例子。

假设,模块 app.js 中用到了三个模块,分别是 jquery、math 和 exception。用到它们的逻辑是:
1.首先通过 math 模块进行一大坨计算
2.然后在最最最末尾,通过 jquery 选择器将计算结果显示在页面上。
3.在显示前,如果计算抛出了异常,则会用到异常模块 exception 将结果友好地显示在页面上

AMD 的模块预加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//app.js
require(['jquery', 'math', 'exception'], function($, math, exception){
//当执行这里面的脚本时,依赖的三个模块都已经加载完了!
var result = {}; //math的最终计算结果
//使用math
math.doSomething();
...
...
//使用exception
if(result.exception){
result.msg = exception( result.exception );
}
//使用jquery
$('#result').html( result.msg );
});

CMD 的模块按需加载 - 懒加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//app.js
define(function(require, exports, module){
//当执行这里的脚本时,依赖的三个模块都还没有加载呢!下面是用到谁了,才会加载谁...
//加载math模块,并通过它进行一系列计算
var math = require('./math');
var result = {}; //math的最终计算结果
math.doSomething();
...
...
//若计算结果有异常,则加载exception模块,对异常信息进行加工
if(result.exception){
var exception = require('./exception');
result.msg = exception( result.exception );
}
//加载jquery,并显示结果
var $ = require('./jquery');
$('#result').html( result.msg );
});

结合上面的例子,来理解下 CMD 对模块的按需加载:

  1. 当开始执行脚本的时候,
    AMD 是那三个模块都已加载完成了
    而 CMD 是还没开始加载呢,下面等用到的时候,再 require() 加载
  2. 当某个模块是动态加载的,比如 exception 模块,只有当计算结果出现异常时才会加载的时候,
    AMD 是把依赖的都提前加载好了,不管代码里是否会真正用到 exception 模块;
    CMD 是等用到了再 require() 加载

当然,上面的例子很生硬,只为了单纯地说明什么是“预加载” 什么是 “懒加载”。
因为,AMD 也是可以实现模块的动态加载的,详见 对 requireJS 的介绍;而 CMD 同时也是支持异步加载的。
由于自己还在学习requireJS和SeaJS中,故对两者之间的区别和pk暂时保持沉默。关于更多 AMD 和 CMD 区别的“口舌之战”详见 AMD 和 CMD 的区别

参考

https://github.com/seajs/seajs/issues/242

文章目录
  1. 1. CMD 简介
  2. 2. CMD 规范的 API
    1. 2.1. define()
      1. 2.1.1. factory()
        1. 2.1.1.1. 加载模块 require
        2. 2.1.1.2. 提供模块接口
        3. 2.1.1.3. module 对象
    2. 2.2. define.cmd
  3. 3. 小结
  4. 4. 参考