JS 模块化

JS模块化

在ES6模块化规范出来之前,有AMD,CMD,CommonJS等模块化规范。AMD和CommonJS都是运行时加载,ES6是编译时加载也叫静态加载。

CommonJS

nodejs环境下(服务器端)的JS模块化规范

  1. 暴露模块:
module.exports = value
exports.xxx = value

暴露的本质是暴露的exports对象。
exports是module.exports的一个引用,exports指向的是module.exports

  • module.exports和exports的区别:
    exports.xxx就是对exports对象添加属性,可以添加多个属性。
    module.exports在一个js文件里,只能写一次,否则后面的会覆盖前面的。
    module.exports可以赋值一个对象,而exports却不可以。
  1. 引入模块:require
    一require就会执行模块里的代码。
    每个模块都是单例的,无论加载(require)多少次,都只会执行一遍,以后加载的都是它的缓存。

CommonJS 模块就是对象,输入时必须查找对象属性。

// CommonJS模块
let { stat, exists, readfile } = require('fs');

// 等同于
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;

上面代码的实质是整体加载fs模块(即加载fs的所有方法),生成一个对象(_fs),然后再从这个对象上面读取 3 个方法。这种加载称为“运行时加载”,因为只有运行时才能得到这个对象,导致完全没办法在编译时做“静态优化”。

browserify

https://browserify.org/
在浏览器端使用commonJS规范。
浏览器没有定义require方法,browserify可以让浏览器像node一样使用require方法。

npm install browserify -g
npm install browserify --save-dev
browserify main.js -o bundle.js   //打包

browserify会解析require()方法的AST,遍历整个项目的依赖图。

AMD

浏览器端的JS模块化规范。
AMD:Asynchronous module definition,异步的模块定义
需要引入require.js。
https://requirejs.org/

define( id, dependencies, factory);

  • 第一个参数,id 为字符串类型,为可选参数,为模块的标识。如果此标识不存在,模块的标识则为此脚本的文件名称,必要时还包含此文件的路径。
  • 第二个参数,dependencies为字符串数组,为当前模块依赖的其他模块标识。
  • 第三个参数,factory为function,其参数对应依赖模块,是一个需要进行实例化的函数或者一个对象。

require([module], callback);

异步,require指定加载的模块,等到模块加载完成,回调函数就会执行模块里的代码。回调函数的参数与[module]是按顺序一一对应的。
无论加载(require)多少次,都只会执行一遍,以后加载的都是它的缓存。

requireJs

https://requirejs.org/

  • requireJS总是动态地请求依赖的JS文件,所以必然涉及到一个JS文件的路径解析问题,requireJS默认采用一种baseUrl + moduleID的解析方式,requireJS对它的处理遵循如下规则:
      1、在没有使用data-main和config的情况下,baseUrl默认为当前页面的目录
      2、在有data-main的情况下,main.js前面的部分就是baseUrl,比如上面的js/
      3、在有config的情况下,baseUrl以config配置的为准
      上述三种方式,优先级由低到高排列。
require.config({
    baseUrl: 'js/modules',
    path:{
        moduleA: 'moduleA',
        moduleB: 'moduleB'
    }
})

requireJS以一个相对于baseUrl的地址来加载所有的代码。页面顶层script标签含有一个特殊的属性data-main,require.js使用它来启动脚本加载过程,而baseUrl一般设置到与该属性相一致的目录。

<script data-main="js/main.js" src="scripts/require.js"></script>

CMD seajs

seajs官网已经不存在了
https://seajs.github.io/seajs/docs/#intro
CMD暴露模块用的是Commonjs的规范,导入模块用的是AMD的规范。

//定义没有依赖的模块 module1.js
define(function(require, exports, module){
    module.exports = value;
    exports.xxx = value;
})

//定义有依赖的模块
define(function(require, exports, module){
    //引入依赖模块(同步)
    var m2 = require('./module2');
    //引入依赖模块(异步)
    require.async('./module3', function(m3){

    })
    //暴露模块
    exports.xxx = value;
})

//引入模块 index.js
define(function(require){
    var m1 = require('./module1');
})

//在html中引入
<script src='js/libs/sea.js'></script>
<script>
    seajs.config({
        base: "./js/"
    });
    seajs.use("index");
</script>

ESModule

https://es6.ruanyifeng.com/
ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。import命令是编译阶段执行的,在代码运行之前。

// ES6模块
import { stat, exists, readFile } from 'fs';

上面代码的实质是从fs模块加载 3 个方法,其他方法不加载。这种加载称为“编译时加载”或者静态加载,即 ES6 可以在编译时就完成模块加载,效率要比 CommonJS 模块的加载方式高。当然,这也导致了没法引用 ES6 模块本身,因为它不是对象。

es6module需要编译转换才能在浏览器端使用es6。

npx babel js/src --out-dir lib
  • 2.用browserify将commonjs转换为在浏览器端可以解析的
browserify .\lib\main.js -o dist/bundle.js

采用ES6Module规范,每次都需要执行打包编译的命令才能在浏览器端使用,因此需要一个打包工具自动完成打包。webpack

浏览器加载

默认情况下,浏览器是同步加载 JavaScript 脚本,即渲染引擎遇到script标签就会停下来,等到执行完脚本,再继续向下渲染。如果是外部脚本,还必须加入脚本下载的时间。

如果脚本体积很大,下载和执行的时间就会很长,因此造成浏览器堵塞,用户会感觉到浏览器“卡死”了,没有任何响应。这显然是很不好的体验,所以浏览器允许脚本异步加载,下面就是两种异步加载的语法。

<script src="path/to/myModule.js" defer></script>
<script src="path/to/myModule.js" async></script>

script标签打开defer或async属性,脚本就会异步加载。渲染引擎遇到这一行命令,就会开始下载外部脚本,但不会等它下载和执行,而是直接执行后面的命令。

defer与async的区别

defer要等到整个页面在内存中正常渲染结束(DOM 结构完全生成,以及其他脚本执行完成),才会执行;async一旦下载完,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染。
一句话,defer是“渲染完再执行”,async是“下载完就执行”。
另外,如果有多个defer脚本,会按照它们在页面出现的顺序加载,而多个async脚本是不能保证加载顺序的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值