JS模块化标准CommonJS/AMD/CMD区别和详解
今天接到阿里的电话面试,面试中问到CommonJS AMD CMD这3种JS模块化开发标准的特点和区别。
当时问题回答的不太好,总结了一下,以免大家采坑。
一、CommonJS
CommonJS是NodeJS服务器端的概念 、采用同步加载文件的方式
实例说明:
目前大家项目中使用打包工具webpack就是通过node实现的功能,配置webpack.config.js中使用的module.exports 公布接口这就是CommonJS的标准
1 const path = require('path'); 2 3 module.exports = { 4 entry: './src/index.js', 5 output: { 6 path: path.resolve(__dirname, 'dist'), 7 filename: 'bundle.js' 8 } 9 };
服务器端的Node.js遵循CommonJS规范。核心思想是允许模块通过require 方法来同步加载所要依赖的其他模块,然后通过exports或module.exports来导出需要暴露的接口。
优点:
- 服务器端便于重用
- NPM中已经将近20w个模块包
- 简单并容易使用
缺点:
- 同步的模块方式不适合不适合在浏览器环境中,同步意味着阻塞加载,浏览器资源是异步加载的
- 不能非阻塞的并行加载多个模块
二、AMD
AMD是"Asynchronous Module Definition"的缩写,意思就是"异步模块定义"。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。
我们使用的RequireJS就是AMD的实现框架。
AMD规范只有一个主要接口define(id,dependencies,factory),它要在声明模块的时候指定所有的依赖dependencies,并且还要当做形参传到factory中,对于依赖的模块提前执行,依赖前置。
1 //定义AMD接口规范 2 3 define("module", ["dep1", "dep2"], function(d1, d2) { 4 5 //定义一个模块dep1 dep2是依赖的模块 依赖的模块是前置加载的, 6 7 return someExportedValue; 8 9 });
1 //引用模块 2 3 require(['math'], function (math) { 4 //异步加载math模块 ,在回调函数中调用 5 math.add(2, 3); 6 7 });
三、CMD
CMD(Common Module Definition)模块定义规范 该规范的代表框架是SeaJS CMD 推崇依赖就近,AMD 推崇依赖前置 ,对比上面AMD的define 就一路了然看到二者的区别了
define(function(require, exports, module) { var math= require('./math') //当使用到math模块了才去加载math模块 math.add(1,2) // 此处略去100 行 var tools= require('./tools') // 依赖可以就近书写 tools.getFile() // ... })
最后总结:
目前实现的框架 | 文件加载方式 | 对依赖模块的加载 | |
AMD | RequireJS | 异步加载 | 前置加载 |
CMD | SeaJS |
异步加载 | 延迟加载 |
Command | NodeJS | 同步加载 | 同步加载 |
如果大家还想了解更多关于RequireJS和SeaJS的差别 看看玉伯的文章