RequireJS 详解
RequireJS 是一个基于 AMD(Asynchronous Module Definition,异步模块定义) 规范的 JavaScript 模块加载器,主要解决浏览器端模块化开发的依赖管理、异步加载问题,避免传统 <script> 标签加载的阻塞和依赖混乱问题。
一、核心优势
- 异步加载:模块按需异步加载,避免阻塞页面渲染;
- 依赖管理:明确声明模块依赖,自动按顺序加载依赖模块;
- 模块化封装:隔离模块作用域,避免全局变量污染;
- 跨环境兼容:支持浏览器端,也可配合工具(如 r.js)打包为生产环境的单文件。
二、快速上手
1. 引入 RequireJS
下载 RequireJS(官网),或通过 CDN 引入,在 HTML 中通过 <script> 标签加载,指定入口模块(data-main):
html
<!-- 引入 require.js,并指定入口模块为 main.js -->
<script src="https://cdn.jsdelivr.net/npm/requirejs@2.3.6/require.js" data-main="js/main"></script>
data-main:指定应用的入口模块(后缀.js可省略);- RequireJS 会自动加载
main.js,并以它为起点管理所有模块。
2. 定义模块
RequireJS 中模块通过 define() 定义,分三种场景:
(1)无依赖模块
javascript
// js/modules/hello.js
define(function() {
return {
sayHello: function(name) {
return `Hello, ${name}!`;
}
};
});
(2)有依赖模块
依赖模块通过数组声明,回调函数的参数与依赖一一对应:
javascript
// js/modules/user.js
define(['./hello'], function(hello) { // 依赖同目录的 hello.js
return {
greet: function(username) {
return hello.sayHello(username);
}
};
});
(3)命名模块(不推荐,RequireJS 会自动根据文件路径生成模块名)
javascript
// 显式指定模块名(一般用于第三方库)
define('myModule', ['jquery'], function($) {
return {
init: function() {
$('body').css('background', '#f5f5f5');
}
};
});
3. 加载模块
通过 require() 加载模块并执行逻辑,通常在入口模块 main.js 中使用:
javascript
// js/main.js
// 配置模块路径(可选,推荐)
require.config({
// 基础路径:所有模块的根路径
baseUrl: 'js',
// 路径映射:简化长路径/第三方库别名
paths: {
'jquery': 'https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min', // CDN 加载
'user': 'modules/user', // 本地模块
'hello': 'modules/hello'
},
// 非 AMD 模块适配(如一些全局变量式的库)
shim: {
'underscore': {
exports: '_' // 暴露全局变量 _ 作为模块导出
}
}
});
// 加载并使用模块
require(['jquery', 'user'], function($, user) {
$(document).ready(function() {
const greetMsg = user.greet('RequireJS');
$('body').html(`<h1>${greetMsg}</h1>`);
});
});
三、核心 API 详解
1. define():定义模块
语法:
javascript
// 无依赖
define(function() { /* 模块逻辑,return 导出内容 */ });
// 有依赖
define([依赖1, 依赖2], function(模块1, 模块2) { /* 逻辑 */ });
// 命名模块
define('模块名', [依赖], function() { /* 逻辑 */ });
2. require.config():全局配置
核心配置项:
| 配置项 | 说明 | 示例 |
|---|---|---|
baseUrl |
模块加载的基础路径 | baseUrl: 'js/lib' |
paths |
模块路径映射(可省略 .js,支持 CDN) |
paths: { jquery: 'jquery-3.7.1' } |
shim |
适配非 AMD 模块(暴露变量、声明依赖) | shim: { underscore: { exports: '_' } } |
map |
不同环境加载不同版本模块 | map: { '*': { 'jquery': 'jquery-2' } } |
waitSeconds |
模块加载超时时间(默认 7 秒) | waitSeconds: 10 |
3. require():加载模块并执行
语法:
javascript
require([依赖1, 依赖2], function(模块1, 模块2) {
// 模块加载完成后的逻辑
}, function(err) {
// 加载失败的回调(可选)
console.error('模块加载失败:', err);
});
四、常见场景
1. 加载第三方非 AMD 模块
很多传统库(如 Underscore、Backbone)不是 AMD 模块,需通过 shim 适配:
javascript
require.config({
paths: {
underscore: 'lib/underscore',
backbone: 'lib/backbone'
},
shim: {
underscore: {
exports: '_' // 暴露全局变量 _
},
backbone: {
deps: ['underscore', 'jquery'], // 声明依赖
exports: 'Backbone' // 暴露 Backbone
}
}
});
// 使用
require(['backbone'], function(Backbone) {
console.log(Backbone);
});
2. 动态加载模块
通过 require() 动态加载模块(如用户交互后):
javascript
$('#loadModule').click(function() {
// 动态加载 hello 模块
require(['modules/hello'], function(hello) {
alert(hello.sayHello('动态加载'));
});
});
3. 模块打包(生产环境)
开发阶段模块分散,生产环境需打包为单文件,使用官方工具 r.js:
-
安装 r.js:
npm install -g requirejs; -
创建打包配置文件
build.js:javascript({ baseUrl: 'js', name: 'main', // 入口模块 out: 'js/build/main.min.js', // 输出文件 optimize: 'uglify2' // 压缩方式(uglify2/closure/none) }) -
执行打包:
r.js -o build.js。
五、注意事项
-
模块路径问题 :
baseUrl是相对 HTML 文件的路径,而非配置文件; -
避免全局变量 :模块内通过
return导出,不要随意定义全局变量; -
循环依赖 :AMD 支持循环依赖,但需通过
require回调获取依赖(而非参数):javascript// a.js define(['b'], function(b) { return { foo: function() { return b.bar(); } }; }); // b.js define(['a'], function(a) { return { bar: function() { // 循环依赖时,通过 require 实时获取 a return require('a').foo() + ' bar'; } }; }); -
生产环境优化:务必用 r.js 打包,减少 HTTP 请求;
-
ES6 模块兼容 :RequireJS 也支持加载 ES6 模块(需配置
packages),但现代项目更推荐 ES6 Module + Webpack/Rollup。
六、与 ES6 Module 的区别
| 特性 | RequireJS(AMD) | ES6 Module |
|---|---|---|
| 加载方式 | 异步加载(运行时加载) | 静态加载(编译时确定依赖) |
| 语法 | define/require |
import/export |
| 作用域 | 函数作用域 | 块级作用域 |
| 浏览器支持 | 需加载器(RequireJS) | 现代浏览器原生支持(需 <script type="module">) |
| 动态加载 | 原生支持 require() |
需配合 import() 动态导入 |
注:现代前端项目(React/Vue/Angular)已普遍使用 ES6 Module + 构建工具(Webpack/Vite),但 RequireJS 仍适用于老项目维护、非构建型简单应用。
七、总结
RequireJS 是浏览器端模块化开发的经典解决方案,核心是通过 AMD 规范实现异步模块加载和依赖管理。其优势是轻量、无需构建工具即可使用,适合中小型项目或老项目维护;缺点是语法相对繁琐,现代项目更推荐 ES6 Module + 构建工具。
如果需要具体场景的代码示例(如循环依赖处理、打包优化),可以进一步说明!