模块化编程介绍:
模块就是独立存储实现特定功能的一组方法程序结构
模块化编程就是,程序中都是用模块先分类组织方法,再按需引入并使用模块中的方法
目的:
便于按业务逻辑划分和维护程序结构
便于团队分工协作
模块化的优点:
降低复杂度
提高解耦性
部署方便
避免命名冲突
更好的分离,按需加载
提高复用性
高可维护性
但是当页面中引入过多script时,请求增多,依赖模糊,难以维护
规范:让程序互相之间能顺畅的无缝加载各种模块,而制定的定义模块的标准,称规范
CommonJS 、AMD、CMD、ES6
(1)CommoJS (服务器端模块规范)
便于划分nodejs中各种服务器端功能,比如文件读写,网络通信,HTTP支持等。
规定:
一个单独的js文件就是一个模块,js文件中,module对象,代表当前模块本身
加载模块使用require方法。require方法读取一个js文件并执行,最后返回文件内部的module对象的exports对象属性的内容
require方法使用单例模式创建该模块;
module.exports---exports---export default与import---require区别和联系
CommonJS问题:所有的模块都是同步加载的,在客户端会造成一个模块没有下下来,第二个不会下。从而造成延迟
(2)AMD (Asynchronous Module Definition 异步加载模块):
既能异步加载多个js文件,减少网页加载的等待;又能设置某两个js文件前后加载顺序,管理模块间的依赖性;
所有以来这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会执行;
不是JavaScript原生支持,需要用到RequireJS库
如何使用:
1.定义子模块:
模块必须用特定的define()函数来定义,define()中回调函数的返回值return,决定了模块对外抛出的内容
define("模块名",[其他模块名,...],function(参数,...){ // 成员:变量/方法 return { 要抛出的成员 } }); // 参数是前面数组中引入的模块
2.在主js文件中引入子模块
require(["子模块",...],function(参数,...){ //参数指的是子模块对象 //这里是调用子模块中的成员了 })
3.HTML中,先引入require.js,并引入主js文件:
(1)普通引入
<script src="require.js" data-main="main.js"></script>
(2)优化require.js本身的异步加载速度
<script src="require.js" data-mian="main.js" defer async="true"></script>
注意:无论是define()还是require()中[]里的模块js文件路径,都是相对主js文件的;
原理:define()和require()中写的依赖子模块js,也是使用<script>加载,只不过,不是所有script都在开始时创建好的。而是根据依赖关系,按需动态创建script
AMD的问题:虽然是异步加载,但是即使一个模块没有用到,这个模块也仍然会被下载下来。
(3)CMD (Common Module Definition)
不同于AMD,它的优点是按需加载模块。
需要使用SeaJS实现CMD规范:
1.定义子模块
define(function(require,exports,module){ require() // 同CommonJS中的require() exports别名 //用法同CommonJS中的exports别名用法 module对象 //用法同CommonJS中的module对象用法 })
2.定义主模块,在主模块中,按需加载子模块使用
define(function(require,exports,module){ if(条件){ var {signin,signout,signup}=require("users"); ... }else { alert('没有使用到users.js模块') } }); seajs.config({ // 用于配置基础路径 base:'./js/modules' }); //调用主模块,并用于执行后续的业务操作,回调函数的参数mian指代引入的主模块
seajs.use(["./js/main"],function(main){}
3.在自定义脚本中引入主模块:
<script src="sea.js"></script> <script src="js/mian.js"></script>
执行到这一步,还不是真正的按需加载,require()在代码分析阶段就加载所有模块js,此时需要用到require.async()
require.async("子模块",function(模块对象){ // 后续执行的代码 })
require() VS require.async()
① 加载方式不同:
require()提前加载完,但是暂不执行,等待按需执行
require.async()异步加载,后续代码放在回调函数中按需执行
② 加载阶段不同:
require()在代码分析阶段就加载所有模块js,没有起到节约流量的作用;
require.async()在执行阶段真正按需加载,按需执行
*** CMD如何打包:
合并打包:Grunt。
前提:
① 不能用require.async,必须使用require()
② require中的的路径:同级目录必须加./,下级目录的js必须:子目录名/模块名
如何使用:
--全局安装grunt-cli
npm i -g grunt-cli
--添加package.json
--定义Gruntfile.js
--调用命令合并,压缩模块代码