在了解AMD,CMD/CommomJS规范前,我们先来简单地了解下什么是模块?
简单的说,一个模块就是实现特定功能的文件,有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。当然,模块开发需要遵循一定的规范,否则各用各的就会乱套了。
一、CommomJS
CommonJS就是为JS的表现来制定规范,因为js没有模块的功能所以CommonJS应运而生,它希望js可以在任何地方运行,不只是浏览器中。
Node,CommonJS,浏览器甚至是W3C之间有什么关系呢,找到了个贴切的图:
image.pngCommonJS定义的模块分为:{模块引用(require)} {模块定义(exports)} {模块标识(module)}
require()用来引入外部模块;exports对象用于导出当前模块的方法或变量,唯一的导出口;module对象就代表模块本身。
比如说我们就可以这样用了:
//sum.js
exports.sum = function(){...操作..};
//calculate.js
var math = require('sum');
exports.add = function(n){
return math.sum(val,n);
};
虽说Node遵循CommonJS的规范,但是相比也是做了一些取舍,填了一些新东西的。
二、AMD
CommonJS是主要为了JS在后端的表现制定的,他是不适合前端的,为什么这么说呢?
这需要分析一下浏览器端的js和服务器端js都主要做了哪些事,有什么不同了:
image.png由于Node.js主要用于服务器编程,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用。但是,如果是浏览器环境,要从服务器端加载模块,这时就必须采用非同步模式,于是乎,AMD(异步模块定义)出现,这种规范是异步的加载模块,requireJs应用了这一规范。先定义所有依赖,然后在加载完成后的回调函数中执行:AMD是依赖前置的,换句话说,在解析和执行当前模块之前,模块作者必须指明当前模块所依赖的模块。如
define(['./a','./b'],function(a,b) {
a.doSomething()
b.doSomething()
});
代码一旦运行到此处,能立即知晓依赖。而无需遍历整个函数体找到它的依赖,因此性能有所提升,缺点就是开发者必须显式得指明依赖——这会使得开发工作量变大。比如,当你写到函数体内部几百上千行的时候,忽然发现需要增加一个依赖,你不得不回到函数顶端来将这个依赖添加进数组。
AMD虽然实现了异步加载,但是开始就把所有依赖写出来是不符合书写的逻辑顺序的,能不能像commonJS那样用的时候再require,而且还支持异步加载后再执行呢?
三、CMD
CMD(Common Module Definition)更贴近 CommonJS Modules/1.1 和 Node Modules 规范,一个模块就是一个文件;它推崇依赖就近,想什么时候 require就什么时候加载,实现了懒加载(延迟执行 ) ;它也没有全局 require, 每个API都简单纯粹 。
在 CMD规范中,一个模块就是一个文件。代码的书写格式如下:
define(factory);
factory 为函数时,表示是模块的构造方法。执行该构造方法,可以得到模块向外提供的接口。factory 方法在执行时,默认会传入三个参数:require、exports 和 module
define(function(require, exports, module) {
var a = require('./a');
a.doSomething();
var b = require('./b');
b.doSomething();
});
四、AMD与CMD的比较
AMD和CMD最大的区别是对依赖模块的执行时机处理不同,而不是加载的时机或者方式不同,二者皆为异步加载模块。AMD依赖前置,js可以方便知道依赖模块是谁,立即加载;而CMD就近依赖,需要使用把模块变为字符串解析一遍才知道依赖了那些模块,这也是很多人诟病CMD的一点,牺牲性能来带来开发的便利性,实际上解析模块用的时间短到可以忽略。
网友评论