AMD和CMD都是为了解决浏览器端模块化问题而产生的,AMD规范对应的库函数有 Require.js,CMD规范是在国内发展起来的,对应的库函数有Sea.js。
两者最明显的区别就是在模块定义时对依赖的处理不同
1、AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块
2、CMD推崇就近依赖,只有在用到某个模块的时候再去require
这种区别各有优劣,只是语法上的差距,而且requireJS和SeaJS都支持对方的写法
AMD和CMD最大的区别是对依赖模块的执行时机处理不同,注意不是加载的时机或者方式不同
很多人说requireJS是异步加载模块,SeaJS是同步加载模块,这么理解实际上是不准确的,其实加载模块都是异步的,只不过AMD依赖前置,js可以方便知道依赖模块是谁,立即加载,而CMD就近依赖,需要把模块变为字符串解析一遍才知道依赖了哪些模块,这也是很多人诟病CMD的一点,牺牲性能来带来开发的便利性,实际上解析模块用的时间短到可以忽略。
为什么我们说两个的区别是依赖模块执行时机不同,为什么很多人认为ADM是异步的,CMD是同步的(除了名字的原因。。。)
同样都是异步加载模块,AMD在加载模块完成后就会执行改模块,所有模块都加载执行完后会进入require的回调函数,执行主逻辑,这样的效果就是依赖模块的执行顺序和书写顺序不一定一致,看网络速度,哪个先下载下来,哪个先执行,但是主逻辑一定在所有依赖加载完成后才执行
CMD加载完某个依赖模块后并不执行,只是下载而已,在所有依赖模块加载完成后进入主逻辑,遇到require语句的时候才执行对应的模块,这样模块的执行顺序和书写顺序是完全一致的
这也是很多人说AMD用户体验好,因为没有延迟,依赖模块提前执行了,CMD性能好,因为只有用户需要的时候才执行的原因。
以Sea.js 为例,看下代码执行顺序就明白它们之间的区别了
index.html
<body>
<h1>SeaJs 依赖模块执行顺序</h1>
<script>
seajs.use("/js/main", function() {
console.log('所有逻辑执行结束');
});
</script>
</body>
main.js
define(function(require, exports, module) {
var a = 1;
var b = 1;
var c, d;
var Add = require('./component/add');
c = Add.add(a, b);
console.log("add模块执行结果:" + c)
var Subtract = require('./component/subtract');
d = Subtract.subtract(a, b);
console.log("subtract模块执行结果:" + d);
});
add.js
define(function(require, exports, module) {
console.log('add模块内部逻辑执行中......');
module.exports = {
add: function(a, b) {
return a + b;
}
}
});
subtract.js
define(function(require, exports, module) {
console.log('subtract模块内部逻辑执行中......');
module.exports = {
subtract: function(a, b) {
return a - b;
}
}
});
执行结果如下图:
由以上运行结果,得出 sea.js 依赖就近,加载完某个依赖模块后并不执行,只是下载而已,在所有依赖模块加载完成后进入主逻辑,遇到require语句的时候才执行对应的模块,这样模块的执行顺序和书写顺序是完全一致的
上图是在浏览器中打开index.html,资源的加载顺序,可以看到,每个模块的都需要发出一次http请求,浪费资源,这也是为什么开发时分模块写代码,上线时要把所有模块合并在一起的原因。目的就是为了减少http请求数量,提高页面性能。