模块化规范

模块化:为了解决js文件之间不确定的依赖关系

commonJS

1.commonjs规范下的模块调用是同步的:必须等模块加载完成之后,接下来的代码才能继续运行。所以,该规范主要适用于服务端。因为服务端可以直接从硬盘中调用所需要的模块,这个过程很快。但是客户端如果一个模块过大就会导致页面假死。

2.主要是node,微信小程序在用

3.一个文件就是一个模块,拥有独立作用域

4.提供require引入模块,export导出模块属性方法。exports代表模块本身

5.一个js文件要输出去,只需使用module.export={xxx:你要输出的内容},而在另外一个js中,你要引用什么,就通过var xxxx=require("xxxx")引用进来就行了

6.模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。(当使用require命令加载同一个模块时,不会再执行该模块,而是取到缓存之中的值。也就是说,CommonJS模块无论加载多少次,都只会在第一次加载时运行一次,以后再加载,就返回第一次运行的结果,除非手动清除系统缓存。)

循环加载时,commonjs属于加载时执行,即脚本代码在require时候,就会全部执行。一旦出现某个模块被“循环加载”,只输出已经执行的部分,未执行的部分不输出。

上述代码很明显的表现出此类特点

step1:node c,js

step2:require(./a.js)//执行完a.js中的内容

step2.1:export.done ='a1'; let b = require(./b.js); // 执行b中的代码

step2.2: export.done ='b1'; let a= require(./a.js) //由于发生了循环加载,所以只执行a中的第一句(export.done ='a1';),然后继续执行b.js 输出 <code>b.js-1 a1 b.js-2执行完毕</code>

step2.3: 继续执行b中的代码 将b.done 赋值为b2

step 2.4 : 执行a的剩余部分 a.js-1 b2; a.js-2 执行完毕

step3:require(./b.js) 由于已经执行过了不会再执行b中的代码 所以直接输出b返回值

step4: 输出c.js-1 执行完毕 a2 b2

想不明白就去看阮一峰老师的这篇博客吧http://www.ruanyifeng.com/blog/2015/11/circular-dependency.html

7.CommonJs模块的加载机制是,输入的是被输出的值的拷贝,即,一旦输出一个值,模块内部的变化影响不到这个值
对于基本数据类型,属于复制。即会被模块缓存。同时,在另一个模块可以对该模块输出的变量重新赋值。对于复杂数据类型,属于浅拷贝。由于两个模块引用的对象指向同一个内存空间,因此对该模块的值做修改时会影响另一个模块。
当使用require命令加载某个模块时,就会运行整个模块的代码。
循环加载时,属于加载时执行。即脚本代码在require的时候,就会全部执行。一旦出现某个模块被"循环加载",就只输出已经执行的部分,还未执行的部分不会输出。
 

 

AMD(异步模块定义)

1.异步的,模块加载不影响后面语句运行。主要适用于浏览器客户端

2.目前使用该规范的典型代表require.js和curl.js

3.所有依赖某些模块的语句均放置在回调函数中

4.提供全局define函数(方法)来定义模块,require引入模块,exports导出模块

5.依赖前置,尽早的执行模块依赖,执行顺序不一定

使用AMD规范进行页面开发需要用到对应的库函数RequireJS。实际上AMD 是 RequireJS 在推广过程中对模块定义的规范化的产出。

requirejs 在实现JavaScript模块化开发的同时,主要是解决2个问题:

    1、多个js模块相互引用问题,被依赖模块需早与依赖模块加载。

    2、js加载的会阻塞浏览器页面渲染,加载文件越多,页面失去响应时间越长 

AMD语法:定义了一个自由变量或者说是全局变量 define 的函数。

define( id?, dependencies?, factory )    

    1、id 为字符串类型,表示了模块标识,为可选参数。若不存在则模块标识应该默认定义为在加载器中被请求脚本的标识。如果存在,那么模块标识必须为顶层的或者一个绝对的标识。

    2、dependencies ,当前模块依赖的模块,已被模块定义的模块标识的数组字面量。

    3、factory,模块初始化要执行的函数或对象。如果为函数,它应该只被执行一次。如果是对象,此对象应该为模块的输出值 

require([dependencies], function(){})   

     require()函数接受两个参数

    1、第一个参数是一个数组,表示所依赖的模块

    2、第二个参数是一个回调函数,当前面指定的模块都加载成功后,回调函数将被调用。加载的模块会以参数形式传入该函数,从而在回调函数内部就可以使用这些模块

    require()函数在加载依赖的函数的时候是异步加载的,这样浏览器不会失去响应,它指定的回调函数,只有前面的模块都加载成功后,才会运行,解决了依赖性的问题。
 

 

CMD(通用模块定义)

其实CMD与AMD规范并没什么本质的区别,区别在于他们对依赖模块的执行时机处理不同。虽然两者都是异步加载模块,但是AMD依赖前置,js可以方便知道依赖模块是谁,要依赖什么js那就先加载进来,至于你要依赖这些js来干吗得先等着,等我加载完了资源再商量;而CMD就近依赖,需要使用这个依赖模块时,我再加载进来用。

语法:

define(function(require,exports,module){...}) ,factory是一个函数,提供equire, exports, module三个参数:

    1、require 是一个方法,接受模块标识作为唯一参数,用来获取其他模块提供的接口:require(id)

    2、exports 是一个对象,用来向外提供模块接口

    3、module 是一个对象,上面存储了与当前模块相关联的一些属性和方法
 

AMD和CMD区别

AMD和CMD最大的区别是对依赖模块的执行时机处理不同:

    1、AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块

    2、CMD推崇就近依赖,只有在用到某个模块的时候再去require

不同点体现如下:

1、异步加载模块

    requireJS,SeaJS加载模块都是异步的,只不过AMD依赖前置,JS可以方便知道依赖模块是谁,立即加载。CMD就近依赖,需要使用把模块变为字符串解析一遍才知道依赖了那些模块。

2、依赖模块执行时机不同

       AMD在加载模块完成后就会执行改模块,所有依赖模块都加载执行完后会进入require的回调函数执行主逻辑,依赖模块的执行顺序和书写顺序不一定一致,主逻辑一定在所有依赖加载完成后才执行。

      CMD加载完某个依赖模块后并不执行,只是下载而已,在所有依赖模块加载完成后进入主逻辑,遇到require语句的时候才执行对应的模块,这样模块的执行顺序和书写顺序是完全一致的。
 

 

总结

自从es2015出来之后,AMD和CMD规范用的越来越少了,但是并不代表这些完全失去了可用性,考虑到浏览器的兼容性,虽然现在浏览器环境对es6的支持越来越完善了,但考虑对一些低版本的浏览器支持,很多在写es6的时候还是会使用babel对es6做一层转换,比如结合webpack配置去打包一个es6语法的js组件,打包出来会是UMD规范的,这是兼容性比较强的一种规范。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值