咱们来玩乐高积木吧html
模块化Js已经成为了老生常谈,不过在JavaScript设计之初,因为定位的问题并无提供类的功能,开发者须要模拟出相似的功能,来隔离、组织复杂的JavaScript代码。以前的闭包也好,自执行函数也好,都是模块化的一些尝试,直到CommonJs
规范推出以后,模块化Js才真正迅猛发展起来。node
从时间点上来讲:浏览器
Node遵循CommonJs
模块化规范,NPM
包管理系统发展如此迅猛就是CommonJs
模块化规范的最佳实践缓存
后来在CommonJs
的基础上衍生出了AMD/CMD
规范,其各自的实践分别是RequireJS
和SeaJs
服务器
CommonJs规范遵循的是同步加载模块规范,即:网络
var A = require(./module/a); A.funA(); var B = require(./module/b); B.funB();
即只有a.js加载完之后,才能接着向下执行A.funA();
才能接着向下加载b.js, 等b.js加载完以后,才能向下执行B.funB();
。但这种同步串行的加载方式确对效率并无多大影响,由于CommonJs
是在Node上运行,处于服务器环境,服务器环境对模块的加载等同于硬盘的读写速度,是很是很是快的。闭包
AMD/CMD
遵循的是异步加载模块规范,拿CMD
规范的SeaJs
举例:异步
define(function(require,exports,module){ require.async('./module/a', function(){alert(1)} require.async('./module/b', function(){alert(2)} });
其中,alert(1) 和alert(2)的执行顺序是不固定的,由于是采用异步加载模块的方式,a模块和b模块是并行加载的 ,谁先加载完毕,谁先掉用回调. 由于网络和文件大小的缘由, 固然有多是b模块先加载完毕,因此多是alert(2)先执行.async
由于requireJs(AMD)
和SeaJs(CMD)
都是运行在客户端浏览器上的. 模块的加载速度和网络情况有关系,加载状况是很是不稳定,若是采用同步串行加载的方式,会出现由于前面的模块加载耗时太长而阻塞了它以后的模块的加载. 因此AMD/CMD
才有了异步的解决方案模块化
(固然,AMD/CMD
也支持同步加载)
按需加载是模块化Js引申出来的概念.咱们可让特定的页面加载特定的JS,就像搭积木恰好把房子搭起来同样,用Js模块组合的方式能够项目搭建起来,保证不缺乏任何一个必要的模块,也保证不会有任何一个多余的模块.
若是index.html只须要弹窗功能和滑动功能,就只加载pop.js和slip.js
提及来却是挺简单,但实际上呢?
实际上也很是简单,拿seaJS
举例来讲,页面index.html引用了Sea.js后,就能够以index.js为加载入口,对页面所需的七七八八的JS模块进行加载:
index.html:
<script src="static/js/lib/sea.js" id="seaJSnode"></script> <script> seaJS.use("./index.js"); </script>
其中index.js:
define(function(require,exports,module){ //引入模块a var A = require('./module/a'); //引入模块b var B = require('./module/b') ... });
其中a.js又依赖了其余的模块:
define(function(require,exports,module){ //引入模块c var C = require('./module/c'); ... });
无论这个依赖关系有多复杂,层级有多深,seaJS的模块加载器会递归找到全部页面index.html依赖的Js,就拿例子来讲,和index.html有关的依赖有 入口文件index.js
和它依赖的a.js, b.js
,而且还有a.js
依赖的 c.js
因此最后index.html实际上会加载index.js, a.js, b.js , c.js
这样就实现了页面须要什么模块,就加载什么模块(和这些模块依赖的模块),从而实现了按需加载。
但有同窗估计又想到了,这个地方有个小缺陷,虽然模块化Js使得加载逻辑更清晰了,可是如此碎片化的Js会增长页面http的请求数,从而影响页面的加载速度。
没错,因此咱们一般在上线前会利用自动化工具对当前页面依赖的全部Js作一个合并处理,即合并压缩成一个Js文件, 这样能最大程度上的利用浏览器缓存,减小Http请求数。
(注:Js模块书写的时候请尽可能避免循环引用的问题,即a.js
引用了c.js
,反过来c.js
又引用了a.js
. 这确定是模块书写不规范形成的,请检查这两个模块的逻辑是否有重叠. 固然,除此以外循环引用仍是有别的办法解决的,这里就不提了)
总而言之,模块化Js目前有两大规范(固然要说成三种规范也能够,不过在做者本人看来AMD/CMD并无本质上的区别)
CommonJS
同步加载模块规范,运行在服务端
AMD/CMD
异步加载模块规范,运行在客户端
由于CommonJs规范在服务器端的同步串行加载Js模块的方式并不适用于客户端浏览器,因此才有了AMD/CMD规范延伸出异步并行加载Js模块的方式。
由于有了Js模块化的概念,才有了Js按需加载的概念。