模块化
无模块化的时代
开始的开始,我们都是孩子。
最开始是没有模块化这一说的,都是script标签异步引入。
CommonJS
服务端的JavaScript——Nodejs使用了CommonJS并将其发扬光大,这标志着JavaScript模块化正式登上历史的舞台。
- 定义模块
- 每个文件就是一个模块,每个模块都是一个单独的作用域
- 模块输出
- 模块只有一个出口module.exports
- 加载模块
- require('lodash')
我们发现require是同步的。模块系统需要同步读取模块文件内容,并编译执行以得到模块接口。 这在服务器端实现很简单,也很自然,然而, 想在浏览器端实现问题却很多。
AMD
Asynchronous Module Definition
AMD规范的代表作就是requirejs。
requirejs解决了两个问题:
- 多依赖问题——多个js文件可能有依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器
- 阻塞问题——js加载的时候浏览器会停止页面渲染,加载文件越多,页面失去响应时间越长
// 定义模块 myModule.js
define(['dependency'], function(){
var name = 'Byron';
function printName(){
console.log(name);
}
return {
printName: printName
};
});
// 加载模块
require(['myModule'], function (my){
my.printName();
});
require()函数在加载依赖的函数的时候是异步加载的,这样浏览器不会失去响应,它指定的回调函数,只有前面的模块都加载成功后,才会运行,解决了依赖性的问题。
CMD
Common Module Definition
CMD规范的代表作就是seajs。
seajs解决的问题和requirejs是一样的。多依赖问题和阻塞问题。
// 定义模块 myModule.js
define(function(require, exports, module) {
var $ = require('jquery.js')
$('div').addClass('active');
});
// 加载模块
seajs.use(['myModule.js'], function(my){
});
seajs原理参阅:
AMD与CMD区别
下面的例子一目了然
/** AMD写法 **/
define(["a", "b", "c", "d", "e", "f"], function(a, b, c, d, e, f) {
// 等于在最前面声明并初始化了要用到的所有模块
a.doSomething();
if (false) {
// 即便没用到某个模块 b,但 b 还是提前执行了
b.doSomething()
}
});
/** CMD写法 **/
define(function(require, exports, module) {
var a = require('./a'); //在需要时申明
a.doSomething();
if (false) {
var b = require('./b');
b.doSomething();
}
});
最明显的区别是
- AMD依赖前置
- CMD依赖就近
AMD在模块加载完成后就会执行该模块,所有模块加载完成进入回调函数,执行主逻辑。 这个就导致了,依赖执行的顺序和加载的顺序不一致。完全取决于哪个先下载下来。
CMD加载摸个依赖后并不执行,只是下载而已。所有依赖加载完成后进入主逻辑,遇到require才执行 对应的模块,这样模块的执行顺序和书写顺序完全一致。
ES6 Module
这个其实就是类似CommonJS了,同步的。