CommonJs, CMD/AMD,ES6 Modules都是前端模块化规范讨论的点,以下就这几种模块规范作简单总结。
-
CommonJs
- CommonJs一般用于服务端,Nodejs就是CommonJS的主要实践者;
- 四个重要的环境变量为模块化提供支持:module,exports,require,global,用module.exports定义当前模块对外输出的接口,用require加载模块;
//暴露模块 module.exports = value; //或者 exports.xxx = value; //引入模块 const xxx = require('xxx');
- 在CommonJs中,一个文件就是一个模块,拥有单独的作用域,不会污染全局作用域;
- 当module.exports与exports同时存在的时候,module.exports会覆盖exports, 如果模块内全是exports,就等同于module.exports,exports其实就是module.exports的子集;
- 使用require加载模块时,模块会在第一次加载时执行脚本,并在内存中缓存,会生成一个对象;所以再次require的时候,会在缓存中取值。
{ id: '...', exports: { ... }, loaded: true, ... }
- CommonJs是采用同步的方式加载,只有在require执行的时候,才会去执行加载;
- 在服务端中,模块文件都存储在本地磁盘中,读取非常快,所以使用CommonJs同步加载不会有问题;但是如果在浏览器端,由于网络原因,使用异步加载的方式更合理。
-
AMD/CMD(异步模块定义/通用模块定义)
- AMD和CMD都是用来解决浏览器需要异步加载的问题,比如多个js文件可能会存在依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器;js加载的时候页面会停止渲染没加载文件越多,页面失去响应的时间就越长等。
- AMD异步模块定义,是RequireJS在推广过程中模块定义的规范化产出。AMD规定模块采用异步方式加载模块,模块加载不影响后面语句的运行。
// 定义moduleA,依赖a.b define(['./a','./b'], function(a, b){ a.doSomething(); b.doSomething(); }) //使用 // 使用 require(['./moduleA'], function(moduleA) { // ... })
CMD对应的是sea.js,是阿里玉伯团队提出的概念。sea.js 推崇一个模块一个文件,遵循统一的写法,所以其文件名经常作为模块id使用。
define(function(require, exports, module) { var a = require('./a') a.doSomething() var b = require('./b') b.doSomething() })
AMD和CMD的主要区别是:AMD推崇依赖前置,提前执行(提前加载);而CMD推崇就近,延迟执行(按需加载);这一点跟script中的async和defer很像。相比来说,AMD用户体验好,因为没有延迟,CDM性能好,因为用户需要的时候才去加载。
-
ES6 Modules
- ES6在语言标准层面上,实现了模块功能,旨在成为浏览器与服务器通用的模块规范。
- 模块主要由两个命令构成:import与export,export用于导出,import用于引入。
- ES6 Modules在编译时就引入模块代码,而不是在运行时才加载。
- ES6 Modules与CommonJs的差异:1)CommonJs模块输出的是值的拷贝,ES6模块输出的是值的引用。2)CommonJs是运行时加载,ES6 Moduels是编译时加载。3)CommonJs输出的是整个对象,而import可以按需引入。