一.为什么前端需要模块化
随着前端的不断发展,前端已经不仅仅是一个简单依据需求完成网页开发的过程,如何提高网页开发效率,提高代码复用率,降低块与块之间的耦合性是我们需要思考的问题,而前端的组件化、模块化正是解决这样的问题。
二.模块化与组件化
1. 什么是前端模块化
-
模块化侧重的功能的封装,主要是针对Javascript代码,隔离、组织复制的javascript代码,将它封装成一个个具有特定功能的的模块
-
模块可以通过传递参数的不同修改这个功能的的相关配置,每个模块都是一个单独的作用域,根据需要调用。
-
一个模块的实现可以依赖其它模块。
2. 什么是组件化
组件化更多关注的UI部分,页面的每个部件,比如头部,内容区,弹出框甚至确认按钮都可以成为一个组件,每个组件有独立的HTML、css、js代码。 可以根据需要把它放在页面的任意部位,也可以和其他组件一起形成新的组件。一个页面是各个组件的结合,可以根据需要进行组装
三. AMD,CMD,CommonJs和ES6
- AMD,CMD,CommonJs和ES6是什么?
AMD,CMD,CommonJs和ES6都是前端模块开发的规范(标准) CMD: CMD规范全称Common Module Definition,该规范明确了模块的基本书写格式和基本交互规则,即定义了一组模块化开发的接口
- 它们之间有什么区别?
模块化规范 | 代表作 | 定义 | 区别 |
---|---|---|---|
AMD | RequireJs | 是require.js在推广过程中对模块化定义规范(ECMA组织标准之下指定的一套语言) | require()函数在加载依赖的函数的时候是异步加载的,这样浏览器不会失去响应,它指定的回调函数,只有前面的模块都加载成功后,才会运行,解决了依赖性的问题。 |
CMD | SeaJs | sea.js在推广过程中对模块化定义规范(淘宝玉伯大牛) | CMD 即Common Module Definition通用模块定义,SeaJS要解决的问题和requireJS一样,只不过在模块定义方式和模块加载(可以说运行、解析)时机上有所不同 |
CommonJs | nodeJs | 根据CommonJS规范,一个单独的文件就是一个模块。加载模块使用require方法,该方法读取一个文件并执行,最后返回文件内部的exports对象。 | CommonJS 加载模块是同步的,所以只有加载完成才能执行后面的操作。像Node.js主要用于服务器的编程,加载的模块文件一般都已经存在本地硬盘,所以加载起来比较快,不用考虑异步加载的方式,所以CommonJS规范比较适用。但如果是浏览器环境,要从服务器加载模块,这是就必须采用异步模式。所以就有了AMD/CMD解决方案。 |
demo:
AMD
# 1.异步加载类库,
# 2.依赖前置: 需要的时候在最前面先加载,加载完成后再执行回调(不过 RequireJS 从 2.0 开始,也改成可以延迟执行)
# 3.依赖文件jq,只有成功加载后,回调才会执行
define(['jquery.js', '', ...], function($) {
...
$('xx').val()
})
CMD
# 1.异步加载类库,
# 2.依赖就进: 需要的时候再引入
define(function(require, exports, module) {
var $ = require('jquery'); // 引入依赖
$('xx').val()
})
1、从seajs.use方法入口,开始加载use到的模块。
2、use到的模块这时mod缓存当中一定是不存在的。seajs创建一个新的mod,赋予一些初始的状态。
3、执行mod.load方法
4、一堆逻辑之后走到seajs.request方法,请求模块文件。模块加载完成之后,执行define方法。
5、define方法分析提取模块的依赖模块,保存起来。缓存factory但不执行。
6、模块的依赖模块再被加载,如果继续有依赖模块,则继续加载。直至所有被依赖的模块都加载完毕。
7、所有的模块加载完毕之后,执行use方法的callback.
8、模块内部逻辑从callback开始执行。require方法在这个过程当中才被执行。
CommonJs
// 1.同步(服务端使用,即NodeJs)
var $ = require('jquery');
// 必须等待jquery加载完成,下面执行才有意义
$('xx').val()
ES6
# 1.每一个模块只加载一次, 每一个JS只执行一次, 如果下次再去加载同目录下同文件,直接从内存中读取。一个模块就是一个单例,或者说就是一个对象;
# 2.每一个模块内声明的变量都是局部变量, 不会污染全局作用域;
# 3.模块内部的变量或者函数可以通过export导出;
# 4.一个模块可以导入别的模块
例1:
#导出:
export default $
#引入:
import $ from 'jquery'
$('xx').val()
例2:
# a.js
export const text = 'hello';
//导出函数
export function square(x) {
return x * x;
}
# main.js
import { text, square } from 'a.js';
console.log(text, square(2))
四.区别AMD和CMD
- 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy aspossible.
- CMD 推崇依赖就近,AMD 推崇依赖前置。
- AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。比如 AMD 里,require 分全局 require 和局部 require,都叫 require。CMD 里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use 来实现模块系统的加载启动。CMD 里,每个 API 都简单纯粹。
五.个人理解
其实我是这样理解的: 异步加载模块就是加载模块的过程不阻塞,同步就是一个文件一个文件的加载,会阻塞(第一个文件未加载完成就会等待)。不管是异步加载还是同步加载,等这些文件加载完成了,才有下一步的执行代码的说法。