学学AMD & CMD

虽然到现在接触前端这一行也有将近一年半的时间了,自己对于前端模块化开发这一块的概念还一直是停留在知道前端领域有AMD和CMD这两个规范,它们是用来解决你的前端开发流程中的模块化加载的问题的。但是却没有在项目中的真正实践,所以这段时间要好好的花时间学习下这块的内容,并且能在以后的项目中真正的去实践一把。

对于AMD和CMD这两个东西,一个是异步模块规范(Asynchronous Module Definition),一个是通用模块规范(Common Module Definition);AMD的典型实践是国外大神James Burke开发的Require.js,CMD的典型实践则是国内玉伯大神推出的Sea.js

说说AMD:

对AMD来说,它的主要特点是:异步加载模块,依赖前置,提前执行。

首先来看异步加载模块,

那依赖前置和提前执行又是什么意思呢?

再看CMD:

在详细的去了解 CMD 之前,我们先来了解下 CommonJS。

CommonJS规范:

通过require就可以引入一个module,一个module通过exports来导出对外暴露的属性接口,在一个module里面没有通过exports暴露出来的变量都是相对于module私有的。

  • 模块引用:require

require()用来引入外部模块

  • 模块定义:exports

exports对象用于导出当前模块的方法或变量

  • 模块标识:module

module对象就代表当前模块变量本身

举例:

1
2
3
4
5
6
7
8
9
10
11
// a.js
function a () {
console.log(’a.js’);
}
module.exports = {
a: a
};

// main.js
var AModule = require(‘./a.js’);
AModule.a();

CommonJS主要适用于服务器端js模块的管理(尤其是Node.js),因为在服务端去加载某个依赖文件都是去读取本地硬盘的操作,速度很快;但是对于浏览器端来说同步的去加载某个模块可能会很慢(因为要通过网络向服务端去请求这个模块)。

对CMD来说,它的主要特点是:同步加载模块,依赖就近,提前执行。

下表展示了浏览器端js和服务端js的区别:

服务器端js
浏览器端js
相同的代码需要多次执行
代码需要从一个服务器端分发到各个浏览器端执行
CPU和内存资源是瓶颈
带宽是瓶颈
加载时需要从磁盘中进行加载
加载时需要从

但是对于前端来说,一个最大的问题就是在浏览器加载脚本天生不支持同步的加载,无法通过文件I/O同步的require加载一个js脚本。

CommonJS规范加载模块是同步的,也就是说只有加载完成,才能执行后面的操作。AMD规范则是非同步加载模块,允许指定回调函数。

AMD规范:

异步模块规范 API 定义了一种模块机制,这种机制下,模块和它的依赖可以异步的加载。这个非常适合于浏览器环境,因为同步的加载模块会对性能、可用性、debug调试和跨域访问产生问题。

确实,在浏览器环境下,AMD有着自己独特的优势:

由于源码和浏览器加载的一致,所见即所得,代码编写和debug非常方便。尤其是在多页面的web项目下,不同页面的脚本js都是根据依赖关系异步按需加载的,不用手动处理每个页面加载js脚本的情况。

支持AMD规范的代表有:require.js

CommonJS in Browser:

由于CommonJS的 require 是同步的,在 require 处需要阻塞,这个在浏览器上并没有很好的支持(浏览器只能异步加载脚本,并没有同步的文件I/O),CommonJS 要在 browser 上直接使用则必须有一个 build 的过程,在这个 build 的过程里进行依赖关系的解析与做好映射。

Webpack && Borwserify:

在 browserify 里可以编写 nodejs 一样的代码(即CommonJS以及使用package.json进行module管理),browserify 会递归的解析依赖关系,并把这些依赖的文件全部build成一个bundle文件,在browser端使用则直接用