在上一篇js模块化入门与commonjs解析与应用中详细的解析了关于commonjs模块化规范,commonjs采用的用同步加载方式,这致使它并非浏览器理想的模块化规范。由于浏览器须要到服务器加载文件,请求事件远远大于本机读取的时间,若是文件较多,网络迟缓就会致使页面瘫痪,因此浏览器更但愿可以实现异步加载的方式。css
AMD规范则是异步加载模块,用于指定回调函数。等模块加载完成之后便可调用回调函数。AMD规范得意的产出就是require.js。html
先经过示例来感觉如下AMD规范实现的requirejs的应用:jquery
1.1定义工做区间文件结构webpack
1 cmd//工做区间 2 modules-->依赖模块 3 m1.js-->模块1 4 m2.js-->模块2 5 demo.html-->结构文本 6 demo.js-->js主入口文件 7 require.js-->CMD模块化工具
1.2.1依赖模块代码(m1):web
1 define(function (){ 2 var name = 'm1-amd'; 3 function getName(){ 4 return name; 5 } 6 return {getName};//{getName}同等与{getName:getName} 7 })
1.2.2依赖模块代码(m2):api
1 define(['m1'],function(m1){ 2 var msg = 'm2-amd'; 3 function show(){ 4 console.log(msg,m1.getName()); 5 } 6 return {show}; 7 })
1.3JS主入口文件:数组
1 (function (){ 2 require.config({ 3 paths:{ 4 m2:'./modules/m2', 5 m1:'./modules/m1' 6 } 7 }); 8 require(['m2','jquery'],function(m2,$){ 9 m2.show(); 10 }); 11 })();
1.4在结构文本中引入AMD规范模块化处理工具require.js,并将主入口文件经过自定义属性data-main='主入口文件路径'的方式引入工具中进行处理:浏览器
<script src="./require.js" data-main="./demo.js"></script>
AMD的基本规范的全称“Asynchronous Module Definition”的缩写,意思是“异步加载模块”。它采用异步方式加载模块,模块的加载不影响后面语句的运行。全部依赖这个模块的语句,都定义在一个回调函数中,等到加载完成后,这个回调函数才会运行。服务器
AMD规范其实是requirejs项目在推广过程当中造成的一个产物,先来看看requirejs的基本使用:
requirejs模块定义:define(id?,dependencies?,factory);==>id:可选参数,用来定义模块的标识,若是没有提供该参数,模块标识就取脚本文件名(去掉扩展名)。==>dependencies:用来传入当前模块依赖的模块名称数组。==>factory:工厂方法,模块初始化要执行的函数或对象,若是是函数,它只被执行一次。若是是对象,此对象应该为模块的输出值。
requirejs模块主入口(模块加载):require.config({paths:{foo:'路径'}});==>faths:配置全部依赖模块的路径。在路径配置代码的下方,再经过require(dependencies?,factory)定义主入口文件的依赖关系和回调函数。
在requirejs中还能够实现依赖其余库和插件,有些插件和库定义了requirejs的标准接口,好比jQuery,可是有些没有标准接口,requirejs官方都给出解决方案,能够参考这篇博客:http://www.javashuo.com/article/p-wgendvdq-dh.html。例如我在示例中也测试了jQuery的使用:
1 (function (){ 2 require.config({ 3 paths:{ 4 m2:'./modules/m2', 5 m1:'./modules/m1', 6 jquery:'./jquery-2.0.3' 7 } 8 }); 9 require(['m2','jquery'],function(m2,$){ 10 m2.show(); 11 $('body').css('backgroundColor','#000'); 12 }); 13 })();
关于requirejs更多API能够查看官网的API示例:https://requirejs.org/docs/api.html
在上面一节介绍了AMD规范以及规范实现的requirejs的基本使用,其中提到了AMD相对于Commonjs的优点在于异步加载模块,可是我没由说明这个异步加载在何时触发,到了CMD这里有必要提一下了,AMD规范很重要的一个思想就是依赖前置,意思就是在模块执行前将全部依赖的模块先所有加载到本地。而CMD的加载方式也是异步加载,可是触发加载的时间是在须要某个依赖模块时再去加载,也有人将CMD说成是同步的,这种同步并非表如今资源加载上,而是触发加载的指令与代码执行是同步的,资源加载仍是异步加载模式。
关于Commonjs、AMD、CMD、ES6模块化的异同在最后会由详细的对比分析。
2.1.先来看CMD的基本应用:https://www.zhangxinxu.com/sp/seajs/
2.1.1.定义工做区间文件结构
CMD//工做区间 -->modules//依赖模块 -->m1.js -->m2.js -->m3.js -->m4.js dome.html//结构文本 demo.js//JS主入入口文件 sea.js//模块化工具
2.1.2.m1模块代码
1 define(function(require,exports,module){ 2 var msg = 'm1'; 3 function foo(){ 4 console.log(msg); 5 } 6 module.exports = { 7 foo:foo 8 } 9 })
2.1.3.m2模块代码
1 define(function(require,exports,module){ 2 var msg = 'm2'; 3 function bar(){ 4 console.log(msg); 5 } 6 module.exports = bar; 7 })
2.1.4.m3模块代码
1 define(function(require,exports,module){ 2 var msg = 'm3'; 3 function foo(){ 4 console.log(msg); 5 } 6 exports.foo = foo; 7 })
2.1.5.m4模块代码
1 define(function(require,exports,module){ 2 var msg = 'm4'; 3 // 同步加载 4 var m2 = require('./m2'); 5 m2(); 6 // 异步加载 7 require.async('./m3',function(m3){ 8 m3.foo(); 9 }); 10 function fun(){ 11 console.log(msg); 12 } 13 exports.fun = fun; 14 })
2.1.6.JS主入口文件demo代码
1 define(function(require,exports,module){ 2 var m1 = require('./modules/m1'); 3 m1.foo(); 4 var m4 = require('./modules/m4'); 5 m4.fun(); 6 })
2.1.7.结构文本demo.html引入模块化处理工具sea.js,使用seajs工具对象方法user找到主入口文件并解析执行==>seajs.use('主入口文件路径'):
1 <script src="./sea.js"></script> 2 <script> 3 seajs.use('./demo.js'); 4 </script>
最后代码打印结果:
这里值得咱们关注的是m4打印在m3的前面,这就是CMD依赖就近原则产生的,在执行队列中异步请求须要等主线程执行完成之后才会调用执行,因此m3做为异步加载模块,在这个代码结构中要最后执行。
值得咱们注意的seajs也有同步加载模式直接使用require('模块路径')获取模块,异步模块加载方式须要使用require.async('模块路径',function(模块名称){回调执行内容})。
ES6自带模块化,可使用import关键字引入模块,经过export关键字处处模块,功能较以前几个方案更为强大,可是因为ES6目前没法在浏览器中执行,因此,须要经过babel将不支持的import编译为当前收到普遍支持的require。
1 // 引入默认变量及方法和模块导入的m1 m2变量或方法 2 import theDefault,{m1,m2} from 'lib'; 3 // 引入默认变量及方法 4 import theDefault from 'lib'; 5 // 引入模块导出的m1 m2变量或方法 6 import {m1,m2} from 'lib'; 7 // 引入模块导出的m1而且将m1重命名myName m2变量或者方法 8 import * as myLib from 'lib'; 9 // 只将lib加载进来 没有用来lib中暴露的接口 10 import 'lib'; 11 12 13 // 暴露变量 14 export var a = '123'; 15 // 暴露函数 16 export function myFun(){ 17 18 } 19 // 默认暴露变量函数等 20 export default a = '123'; 21 export function myFun(){}
关于ES6的模块化会在ES6的相关博客中来详细解析,这里只作一些基本介绍。
1.什么是模块化?
答:模块化是指将一个复杂的系统分解为多个模块,方便编码。
2.为何要用模块化?
答:下降复杂性,下降代码耦合度,部署方便,提升效率。
3.模块化的好处?
答:3.1.避免命名冲突,减小变量空间污染;
3.2.更好的分离代码,按序加载;
3.3.更高复用性;
3.4.更高可维护性;
4.Webpack支持性:
AMD、ES Modules(推荐使用)、CommonJS由于webpack是基于nodeJS的,因此有必要了解学习。
5.AMD、CMD、CommonJS模块规范的对比分析:
AMD、CMD可使用插件引入的方式实现JS代码模块化管理,CommonJS不兼容浏览器须要Browserify工具在nodejs环境下转换成浏览器可执行的JS文件。
Commonjs采用同步加载,会在必定程度上增长页面载入时间,若是在这个过程当中出现某个模块错误,会致使页面加载失败。
AMD、CMD采用异步加载,二者的区别就是AMD采用前置预加载模式,CMD采用就近原则加载模式。AMD的体验更好,CMD的性能更优,可是CMD须要考虑异步队列的执行顺序问题,因此这里的更好和更优要相对而言。
(后续深刻研究后再来补充)