2010年前后 AMD(RequireJS)
CommonJS与AMD
时间线
- 2009年:Node.js 发布,同时社区提出 CommonJS 规范(最初叫 ServerJS,后来改名)。
- 目标:给 服务器端 JavaScript 一个统一的模块系统。
- 特点:
require同步加载,本地文件系统读取,没问题。
- 2010年前后:前端社区发现 CommonJS 不适合浏览器(因为浏览器加载 JS 必须异步)。
- 于是提出 AMD(Asynchronous Module Definition),典型实现就是 RequireJS。
- 目标:解决 浏览器端 的异步加载和模块组织问题。
👉 先有 CommonJS(服务端),后有 AMD(浏览器端)。
可以说 AMD 是“把 CommonJS 思路搬到浏览器时,发现同步行不通,只好改成异步”的产物。
差异简述
- CommonJS:面向服务器,关注“文件系统同步加载”。
- AMD:面向浏览器,关注“网络异步加载”。
- 模块化项目的运行:取决于运行环境,
- 在服务器上跑 → 需要服务器端模块化(CommonJS / ES Module)。
- 在浏览器里跑 → 需要浏览器端模块化(AMD / ES Module)。
- 如果项目是 全栈,那就两个环境都得有自己的模块化方案。
背景:为什么要有 AMD?
AMD(Asynchronous Module Definition),也就是 RequireJS 所代表的规范。它是前端在 浏览器端 尝试模块化的一次重要实践,出现在 2009~2010s 前后,正是 前端工程化的起点之一。
前面我们说过 CommonJS(Node.js 的 require):
- 特点:同步加载(运行到
require才去拿模块)。 - 问题:浏览器里用不了。
为什么?
- 浏览器的 JS 加载是通过
<script>标签请求外部文件。 - HTTP 请求是 异步 的,如果在浏览器里用 CommonJS:
const math = require('./math.js');
console.log(math.add(1, 2));
浏览器必须“停下来等待 math.js 下载完”,这会阻塞页面,体验极差。
👉 于是社区提出 AMD:既然浏览器加载 JS 必然是异步的,那就让模块定义和依赖加载都异步化。
AMD 的核心思想
- 异步加载:模块不会阻塞页面渲染。
- 依赖提前声明:你要用什么模块,必须在
define时声明。 - 模块工厂函数:依赖加载完成后,传入工厂函数里,执行并返回模块。
RequireJS 的基本写法
定义模块
// math.js
define([], function() {
function add(a, b) { return a + b; }
function sub(a, b) { return a - b; }
return { add, sub };
});
使用模块
// main.js
define(['math'], function(math) {
console.log(math.add(1, 2)); // 输出 3
});
👉 核心:
define([...依赖...], function(...参数...){...})- 依赖会先异步加载
- 然后把模块对象传入工厂函数的参数
- 加载是异步的,不阻塞页面。
RequireJS 的加载流程
- 页面引入 require.js(核心库)。
<script data-main="main" src="require.js"></script>
- `data-main="main"` 表示从 `main.js` 作为入口模块开始加载。
2. RequireJS 读取 main.js,发现它 define(['math'], ...)。
3. RequireJS 动态创建 <script src="math.js"> 标签,异步下载 math.js。
4. 等 math.js 加载完成后,执行它的工厂函数,返回模块对象。
5. 把 math 传给 main.js 的回调函数,继续执行逻辑。
👉 整个过程全是异步的,不会阻塞页面。
AMD 的优点
- 非阻塞加载:适合浏览器环境。
- 依赖提前声明:一眼能看出模块依赖关系。
- 跨文件模块化:终于摆脱了把所有 JS 写在一个文件里的时代。
- 社区推动:RequireJS 在当时是最流行的前端模块加载器。
AMD 的缺点
- 语法冗长:每个模块都得包裹
define([...], function(){...})。 - 可读性差:嵌套回调多,容易形成“回调地狱”。
- 依赖顺序问题:虽然是异步,但依赖必须显式声明,否则无法保证顺序。
- 与 Node.js 不兼容:AMD(浏览器) vs CommonJS(服务器),生态割裂。
总结
- AMD(RequireJS) 是前端模块化的 过渡方案。
- 它解决了 浏览器端 JS 异步加载 的问题,让模块化在前端真正落地。
- 但它的语法和体验并不理想,后来才有了 CMD(SeaJS,中国提出,更贴近 CommonJS),以及最终的 ES Module(官方标准化)。