模块化详解
- 在讲模块化理解之前,首先得疏理一下,模块的化的发展流程
- 真正的模块开启由于nodejs在2009年发布,带来commonjs,将模块化开发带来白热化时代,那么commonjs的特点是什么,接下来为您介绍:
- 通过requirejs进行模块加载,采用同步加载
- commonjs它只服务于服务端
- 模块加载器和模块解析器
- 模块加载器:采用fs解析文件路径,将相对路径解析绝对文件路径,加载文件代码,并解析执行
- 模块加载器:采用模块加载解析执行字符串代码,通过exports暴露模块; 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
- 模块加载的顺序,按照其在代码中出现的顺序
- 在2010年AMD和2011年CMD两大模块架构大战,将浏览器也引入模块化开发的大潮中,最后在2014年umd的诞生,将commonjs/amd将两大模块进行统一处理;但是cmd它基于amd发展,但是并延续多久最终走向末路,在amd和commonjs成为浏览器和服务端两大阵营,并由umd同一处理,接下来简单介绍一下amd和umd的主要特点
- AMD
- 遵循commonjs模块规范
- 定义全局函数 define(id, dependencies, factory),用于定义模块。dependencies 为依赖的模块数组,在 factory 中需传入形参与之一一对应
- 如果 dependencies 的值中有 require、exports 或module,则与 CommonJS 中的实现保持一致。
- 如果 dependencies 省略不写,则默认为 [‘require’, ‘exports’, ‘module’],factory 中也会默认传入三者
- 如果 factory 为函数,模块可以通过以下三种方式对外暴漏 API:return 任意类型;exports.XModule = XModule、module.exports = XModule。
- 如果 factory 为对象,则该对象即为模块的导出值。
- 浏览器环境,要从服务器端加载模块,这时就必须采用非同步模式
- 异步实现方案jsonp方案实现
- AMD模块定义的方法非常清晰,不会污染全局环境,能够清楚地显示依赖关系。AMD模式可以用于浏览器环境,并且允许非同步加载模块,也可以根据需要动态加载模块
// 定义没有依赖的模块
define(function() {
let msg = 'www.baidu.com'
function getMsg() {
return msg.toUpperCase()
}
return { getMsg } // 暴露模块
})
// alerter.js文件
define(['dataService', 'jquery'], function(dataService, $) {
let name = 'Tom'
function showMsg() {
alert(dataService.getMsg() + ', ' + name)
}
$('body').css('background', 'green')
// 暴露模块
return { showMsg }
})
- 优先判断是否存在 exports 方法,如果存在,则采用 CommonJS 方式加载模块;
- 其次判断是否存在 define 方法,如果存在,则采用 AMD 方式加载模块;
- 最后判断 global 对象上是否定义了所需依赖,如果存在,则直接使用;反之,则抛出异常
- 接下来在 2016 年 5 月年ES官方推出esModule,模块化开发正式进入一个新的浪潮,并被称为es6,接下来简单介绍一下es6的特点:
export const a = 123
import a from 'a.js'
- ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。
- 对基本类型采用值引用
- 动态运行时,静态编译 (
import
语句都是静态执行,export
则是动态绑定的) - esm分为三个流程:构建阶段—>实例化阶段---->执行阶段
- 三阶段解决循环引用:先打标记,循环引用时,看到标记,先不执行;继续执行下面的代码, 等执行阶段后,通过
import
和export
链接到该内存地址
参考文档
前端模块化详解
编程简史系列
commonjs 规范 – 阮一峰