诞生背景
AMD其实已经算是解决了前端模块化开发的问题了,但是!!!但是,因为AMD管理依赖的时候,会把所有的依赖下载到本地,并且立即执行一次。依赖少了还好,多的话,那么多js均要被执行一次,这个内存消耗就不容小觑了。而且最重要的是,执行js会阻塞dom的渲染。用户的直接感觉就是页面初始加载的时候等待的时间较长。然后china有一个叫‘玉伯’的牛人,开发了个类库sea.js。seaJs核心即AMD模块化开发规范
核心规范
CMD(Common Module Definition)更贴近 CommonJS Modules/1.1 和 Node Modules 规范,一个模块就是一个文件;
它推崇 依赖就近 想什么时候 require 就什么时候加载,实现了 懒加载, 延迟执行 (as lazy as possible) ;
经常使用的 API 只有 define, require, require.async, exports, module.exports 这五个。其他 API 有个印象就好。
特性:=====预先下载,延迟执行===
会提前下载好所有requre后的文件,但是并不执行模块内容,直到需要执行的时候才执行
实例代码
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div class="wrapp"> <input type="text"></br> <input type="text"></br> <button>求和</button></br> <div class="sumWrap"></div> </div> <script src="lib/jquery-3.2.1.min.js"></script> <script src="lib/sea.js"></script> <script src="js/app.js"></script> </body> </html>
app.js
/** *模块: *功能:入口 */ seajs.use(['./js/tools'],function (tools) { $('button').click(function () { var num1=$('input:eq(0)').val(); var num2=$('input:eq(1)').val(); var sum=tools.add(num1,num2); $('.sumWrap').text(sum) }) });
tools.js
/** *模块:tools *功能:工具 */ define(function (require, exports, module) { return { add:function (x,y) { var sum= Number(x)+Number(y); var log=require('./log'); log.info('tools>add执行结果为:'+sum); return sum; } } })
log.js
/** *模块:log模块 *功能:打印 */ console.log('cmd log.js文件--我被下载啦') define(function () { console.log('cmd log模块--我被执行啦') return { info:function (str) { console.log(str) }, err:function (str) { console.error(str) } } })
效果
看到没有,cmd会提前把所有的依赖下载到本地资源中,但是并不执行(也叫加载),直到遇到require的时候,才执行。
比如说那个log.js刷新页面看浏览器的network或者source都已经有该文件了,也就是说项目初始化的时候就下载了该模块(即该模块所在的文件,因为cmd推崇一个模块就是一个文件),为测试,我打印了‘log.js被下载啦’
但是log模块并没有执行,点击计算求和的时候,在tools的add方法里有require('log.js'),这个时候,log.js里定义的模块才被加载执行
这就叫做‘依赖后置,使用时才加载(懒加载、 延迟执行)’
这就很好的解决了初始化AMD那样会下载并执行完所有的模块引起的卡屏问题
不过默认下require是同步的,也就是说,require的模块没有执行完,程序是不会继续往下执行的。这样就很类似于nodeJs的commomJS模块开发规范了。
当然如果有些人觉得这样虽然很干净利索,但是还是没有会掉性能优化,那么CMD提供了异步的方案
require.async('[模块a]', function(a) { a.doSomething(); });
但是我觉得,这样这样写太矫情了,就好比你一直吃红薯(写回调),突然吃大米(像传统高级语言那样简单的写同步)很不习惯!!!
作者总结
由于目前浏览器尚不支持模块化CMD规范,所以这些关键字无法被识别,需要先引入库sea.js
补充一点
与AMD不同的小细节,CMD追求与node写法一样,所以也为我们提供了moudule.export,它其实等价于return 关键字,就是大家所说的语法糖。所以tools.js和log.js我可以改成如下这样,效果不变
tools.js
/** *模块:tools *功能:工具 */ define(function (require, exports, module) { var add=function (x,y) { var sum= Number(x)+Number(y); var log=require('./log'); log.info('tools>add执行结果为:'+sum); return sum; } //等价于return module.exports = { add: add }; })
log.js
/** *模块:log模块 *功能:打印 */ console.log('cmd log.js文件--我被下载啦') define(function (require, exports, module) { console.log('cmd log模块--我被执行啦') var info=function (str) { console.log(str) }; var err=function (str) { console.error(str) }; //等价于return module.exports = { info: info, err: err }; })