JS模块化编程(commonJS&AMD&CMD)

模块化编程介绍:

  模块就是独立存储实现特定功能的一组方法程序结构

  模块化编程就是,程序中都是用模块先分类组织方法,再按需引入并使用模块中的方法

  目的:

    便于按业务逻辑划分和维护程序结构

    便于团队分工协作

模块化的优点:

  降低复杂度

  提高解耦性

  部署方便

  避免命名冲突

  更好的分离,按需加载

  提高复用性

  高可维护性

但是当页面中引入过多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

  --调用命令合并,压缩模块代码

原文地址:https://www.cnblogs.com/codexlx/p/12495322.html