RequireJS 加载 JavaScript 模块实战教程

作者:拾光时间:2026-10-30 08:19:32浏览:69

本文详解 RequireJS 如何通过 AMD 规范实现 JavaScript 模块的异步加载与依赖管理。涵盖 script 标签配置、require.config 路径映射、define 模块定义及 domReady 执行时机,结合代码示例解析模块间依赖关系的构建与优化技巧。

RequireJS 异步加载原理与优势

浏览器默认通过 script 标签同步加载 JavaScript,即前一个脚本加载并执行完毕后,才开始加载下一个,直到所有文件加载完成。这种方式要求严格遵循脚本间的依赖顺序,且在加载期间会阻塞浏览器响应,严重影响用户体验。为解决 JavaScript 依赖管理和加载效率问题,出现了多种方案,RequireJS 便是其中一种主流工具。

RequireJS 主要加载符合 AMD(异步模块定义)规范的模块,这类模块通过 define 方法定义,并通过 return 语句暴露方法和变量。虽然 RequireJS 也支持加载非 AMD 标准的模块,但实现过程较为繁琐,本文暂不展开讨论。

使用 RequireJS 加载 JavaScript 主要涉及以下几个核心方面:

  • 在 script 标签中,通过 data-main 属性指定 RequireJS 的入口模块,并设置 async="true"(非 IE 浏览器)或 defer(IE 浏览器)以实现异步加载。
  • 通过 require.config 方法配置模块对应的文件路径。
  • 使用 require 方法声明模块间的依赖关系。

HTML 入口与基础配置

HTML 演示示例如下:


<script src ="js/require.js" defer async="true" data-main="js/main" >

<!--给出requirejs路径,声明为异步加载,指定入口模块为

main.js(可省略.js)-->

主配置文件 main.js 示例:


 require.config({
   //声明模块的位置
   paths: {
     "jquery":"libs/jquery"
     "login" : "libs/login"
   }
   //或使用baseUrl指定所有模块的路径
   baseUrl: "js/libs"
 });
 //使用require加载模块,第一个参数为数组,即要加载的模块,将按数组顺序加载;第二个为回调函数,在全部加载完成后执行。
 require(['jquery','login'],function($,Login){
   alert("jquery and login module load success!");
   Login.do_login();
   //some else
 });

符合 AMD 规范的登录模块定义示例:


 //依赖jquery的定义
 define(['jquery'],function($){
   // some definations
  function do_login(){
    $.post('/sessions/create',{uname:$("#uname").val(),
         password:$("#password").val()},function(data){
     //some 
   });
   return {do_login:do_login};
  } 
 });

//不依赖其他模块的定义
define(function(){
 //some definations
 return {xx:xx};
});

Rails 框架通常不直接应用 JavaScript 加载器,原因有二:一是新版 Rails 的 Asset Pipeline 会将所有 JS 文件打包为单一文件,不存在多文件加载场景;二是 Turbolink 采用的类似 pjax 技术,默认将链接请求改为 AJAX 方式,仅获取 HTML body 部分,保持 head 不变,从而使得 JS 仅在首次打开网站时加载。

模块加载与执行时机控制

案例一:加载 JavaScript 文件


 <script src="./js/require.js"></script> 
   <script> 
  require(["./js/a.js", "./js/b.js"], function() { 
       myFunctionA(); 
       myFunctionB(); 
    }); 
   </script>

在 require 方法中,字符串数组参数允许不同格式的值。若字符串以 ".js" 结尾、以 "/" 开头或是完整 URL,RequireJS 会将其视为直接加载 JavaScript 文件;若字符串格式类似 "my/module",则视为模块,并依据用户配置的 baseUrl 和 paths 加载对应的 JS 文件。具体配置细节将在后文介绍。

需要注意的是,RequireJS 默认并不保证 myFunctionA 和 myFunctionB 一定在页面加载完成后执行。若需确保脚本在页面加载后执行,RequireJS 提供了独立的 domReady 模块。该模块需从 RequireJS 官方网站下载,未包含在核心库中。引入 domReady 模块后,案例一的代码需稍作修改以依赖该模块。

案例二:页面加载后执行 JavaScript


 <script src="./js/require.js"></script> 
   <script> 
  require(["domReady!", "./js/a.js", "./js/b.js"], function() { 
       myFunctionA(); 
       myFunctionB(); 
    }); 
   </script>

执行案例二代码后,通过 Firebug 可观察到 RequireJS 在当前页面为 a.js 和 b.js 分别插入了 script 标签,用于异步下载 JavaScript 文件。async 属性目前获绝大多数浏览器支持,表明该 script 标签内的 JS 文件不会阻塞其他页面内容的下载。

案例三:RequireJS 插入的 script 标签示例


 <script type="text/javascript" charset="utf-8" async="" data-requirecontext="_" 
 data-requiremodule="js/a.js" src="js/a.js"></script>

AMD 规范下的模块定义与依赖

使用 RequireJS 定义 JavaScript 模块

与传统 JavaScript 代码不同,这里的 JavaScript 模块无需访问全局变量。模块化设计使得在需要访问“全局变量”时,可通过依赖关系将其作为参数传递给模块实现体,从而避免在实现中访问或声明全局变量或函数,有效规避了复杂且庞大的命名空间管理问题。

正如 CommonJS 的 AMD 规范所述,定义 JavaScript 模块是通过 define 方法实现的。

下面通过一个简单示例,定义 student 模块和 class 模块,并在主程序中创建 student 对象,将其加入 class 中。

案例四:student 模块(student.js)


 define(function(){ 
   return { 
    createStudent: function(name, gender){ 
       return { 
         name: name, 
         gender: gender 
       }; 
    } 
   }; 
 });

案例五:class 模块(class.js)

 


define(function() { 
 var allStudents = []; 
    return { 
      classID: "001", 
      department: "computer", 
      addToClass: function(student) { 
      allStudents.push(student); 
      }, 
      getClassSize: function() { 
      return allStudents.length; 
      } 
    }; 
   } 
 );

案例六:主程序代码


 require(["js/student", "js/class"], function(student, clz) { 
 clz.addToClass(student.createStudent("Jack", "male")); 
 clz.addToClass(student.createStudent("Rose", "female")); 
 console.log(clz.getClassSize()); // 输出 2 
 });

student 模块和 class 模块均为独立模块。接下来定义一个新模块,该模块依赖 student 和 class 模块,从而将主程序的逻辑也封装进去。

案例七:依赖 student 和 class 模块的 manager 模块(manager.js)

 


define(["js/student", "js/class"], function(student, clz){ 
 return { 
  addNewStudent: function(name, gender){ 
  clz.addToClass(student.createStudent(name, gender)); 
    }, 
  getMyClassSize: function(){ 
  return clz.getClassSize(); 
  } 
   }; 
 });

案例八:新的主程序代码


 require(["js/manager"], function(manager) { 
 manager.addNewStudent("Jack", "male"); 
 manager.addNewStudent("Rose", "female"); 
 console.log(manager.getMyClassSize());// 输出 2 
 });

通过上述代码示例,已清楚了解如何编写模块、使用模块以及定义模块间的依赖关系。此外,还有一些使用技巧需要提示:

尽量避免提供模块 ID。如 AMD 规范所述,ID 是可选的。若提供 ID,在 RequireJS 实现中会影响模块的可移植性,文件位置变更时需手动修改该 ID。

每个 JavaScript 文件仅定义一个模块。模块名称与文件路径的查找算法决定了这种方式是最优的,多个模块和文件会被优化工具进行合并优化。若无法避免模块间的循环依赖,可在模块中增加对“require”模块的依赖,并在代码中直接使用。


require(”dependencyModuleName”)

RequireJS 路径与高级配置

配置 RequireJS:

前文介绍中似乎忽略了一个基本问题:模块名称是如何生成的?当在 require 中引用一个模块时,该模块如何映射到具体的 JavaScript 文件?这涉及到 RequireJS 的配置问题。

最简化的加载 RequireJS 方式如案例2所示。在此情况下,未指定 baseUrl 和 paths。若通过如案例10所示方式,data-main 指定了当前 index.html 目录并行文件夹下的 /js/main.js 作为程序入口,同时 /js 目录也将作为 baseUrl 在其他模块定义时使用。

案例九:载入 require.js


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

因此,前文示例中的所有模块依赖均可去掉“js/”,直接写“student”、“class”、“manager”等。一种更直接的方式是利用 require.config 显式指定 baseUrl 和 paths,如案例十所示。

案例十:配置 RequireJS


 <script type="text/javascript" src="./js/require.js"></script> 
 <script type="text/javascript"> 
 require.config({ 
  baseUrl: "./js", 
  paths: { 
    "some": "some/v1"
  }, 
 waitSeconds: 10 
 }); 
 require( ["some/module", "my/module", "./js/a.js"], 
  function(someModule,  myModule) {} 
 ); 
 </script>

baseUrl 指明所有模块的基础 URL,例如“my/module”所加载的脚本实际为 /js/my/module.js。注意,以 .js 结尾的文件加载时不使用 baseUrl,仍使用当前 index.html 所在的相对路径加载,因此仍需加上“./js/”。若未指定 baseUrl,则使用 data-main 中指定的路径。

paths 中定义的路径用于替换模块中的路径,如上例中 some/module 的具体 JavaScript 文件路径为 /js/some/v1/module.js。waitSeconds 指定加载 JavaScript 文件的最长等待时间,默认值为 7 秒。

另一个重要配置是 packages,它可指定其他符合 CommonJS AMD 规范的目录结构,由此带来丰富的扩展性。例如 Dojo、jQuery 等模块也可通过该配置由 RequireJS 加载。

其他可配置选项还包括 locale、context、deps、callback 等,感兴趣的读者可在 RequireJS 官方网站查阅相关文档。

作者最新文章