使用RequireJS库加载JavaScript模块的实例教程


Posted in Javascript onJune 06, 2016

js通过script标签的默认加载方式是同步的,即第一个script标签内的js加载完成后,才开始加载第二个,以此类推,直至js文件全部加载完毕。且js的依赖关系必须通过script的顺序才能确保;而在js加载期间,浏览器将停止响应,这大大影响了用户体验,基于此,很多解决js以来和加载的方案出现,require js就是其中之一。

requirejs加载的模块,一般为符合AMD标准的模块,即用define定义,用ruturn返回暴露方法、变量的模块;requirejs也可以加载飞AMD标准的模块,但比较麻烦,这次不涉及。

require加载js主涉及以下方面:

  • script 标签data-main属性声明requirejs加载的入口模块,async="true"(非ie) 和defer(ie)标签表明异步加载。
  • require.config配置模块对应的路径
  • require声明依赖关系

html demo

<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的login module定义

//依赖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没有应用js加载器,一方面是新版本的rails的asset pipe会将所有的js文件打包为一个js文件,没有多个js加载的状态,另一方面turbolink使用褒贬参半的所谓pjax技术,默认链接改为ajax方式,只获取html的bod部分,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 来加载相应的模块所在的 JavaScript 文件。配置的部分会在稍后详细介绍。

这里要指出的是,RequireJS 默认情况下并没有保证 myFunctionA 和 myFunctionB 一定是在页面加载完成以后执行的,在有需要保证页面加载以后执行脚本时,RequireJS 提供了一个独立的 domReady 模块,需要去 RequireJS 官方网站下载这个模块,它并没有包含在 RequireJS 中。有了 domReady 模块,案例一 的代码稍做修改加上对 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>

使用 RequireJS 来定义 JavaScript 模块

这里的 JavaScript 模块与传统的 JavaScript 代码不一样的地方在于它无须访问全局的变量。模块化的设计使得 JavaScript 代码在需要访问”全局变量”的时候,都可以通过依赖关系,把这些”全局变量”作为参数传递到模块的实现体里,在实现中就避免了访问或者声明全局的变量或者函数,有效的避免大量而且复杂的命名空间管理。

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

下面我们先来看一个简单的例子,这个例子通过定义一个 student 模块和一个 class 模块,在主程序中实现创建 student 对象并将 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 是可选项,如果提供了,在 RequireJS 的实现中会影响模块的可迁移性,文件位置变化会导致需要手动修改该 ID。

每个 JavaScript 文件只定义一个模块,模块名称和文件路径的查找算法决定了这种方式是最优的,多个的模块和文件会被优化器进行优化。 避免模块的循环依赖,如果实在避免不了,可以模块中加上对”require”模块的依赖,在代码中直接用

require(”dependencyModuleName”)

配置 RequireJS:

前面的介绍中,我们似乎忽略了一个基本问题,模块名字是怎么来的?当我在 require 一个模块时,这个模块是如何映射到具体的 JavaScript 文件上去?这就涉及到如何配置 RequireJS。

最简化的加载 RequireJS 的方式如案例2 所示,在这种情况下,我们没有指定一个 baseUrl 和 paths 给 RequireJS,如果通过如案例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” 等。 一种更为直接的方式显示指定 baseUrl 和 paths 就是利用 require.config 来设置这些参数。如案例十 所示。

案例十. 配置 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指明的是所有模块的 base URL,比如”my/module”所加载的 script实际上就是 /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 的官方网站查阅相关文档。

Javascript 相关文章推荐
Jquery为单选框checkbox绑定单击click事件
Dec 18 Javascript
简述JavaScript中正则表达式的使用方法
Jun 15 Javascript
jQuery实现的调整表格行tr上下顺序
Jan 10 Javascript
老生常谈javascript的面向对象思想
Aug 22 Javascript
jQuery实现动态加载select下拉列表项功能示例
May 31 jQuery
微信小程序支付功能 php后台对接完整代码分享
Jun 12 Javascript
浅谈JavaScript 代码简洁之道
Jan 09 Javascript
js变量声明var使用与不使用的区别详解
Jan 21 Javascript
JavaScript数据结构与算法之二叉树实现查找最小值、最大值、给定值算法示例
Mar 01 Javascript
Vue实现菜单切换功能
Nov 08 Javascript
JavaScript中Object、map、weakmap的区别分析
Dec 15 Javascript
JavaScript展开运算符和剩余运算符的区别详解
Feb 18 Javascript
ionic 上拉菜单(ActionSheet)实例代码
Jun 06 #Javascript
深入理解JavaScript 函数
Jun 06 #Javascript
Node.js的Web模板引擎ejs的入门使用教程
Jun 06 #Javascript
javascript url几种编码方式详解
Jun 06 #Javascript
ionic js 复选框 与普通的 HTML 复选框到底有没区别
Jun 06 #Javascript
ionic js 模型 $ionicModal 可以遮住用户主界面的内容框
Jun 06 #Javascript
JavaScript sort数组排序方法和自我实现排序方法小结
Jun 06 #Javascript
You might like
Laravel 5.5 实现禁用用户注册示例
2019/10/24 PHP
PJ Blog修改-禁止复制的代码和方法
2006/10/25 Javascript
juqery 学习之六 CSS--css、位置、宽高
2011/02/11 Javascript
textarea 控制输入字符字节数(示例代码)
2013/12/27 Javascript
深入理解JavaScript系列(34):设计模式之命令模式详解
2015/03/03 Javascript
JS onkeypress兼容性写法详解
2016/04/27 Javascript
JavaScript  event对象整理及详细介绍
2016/10/10 Javascript
vue.js表格组件开发的实例详解
2016/10/12 Javascript
Javascript中字符串和数字的操作方法整理
2017/01/22 Javascript
正则表达式基本语法及表单验证操作详解【基于JS】
2017/04/07 Javascript
老生常谈js-react组件生命周期
2017/05/02 Javascript
基于vue 动态加载图片src的解决方法
2018/02/05 Javascript
Vue中android4.4不兼容问题的解决方法
2018/09/04 Javascript
vue的全局变量和全局拦截请求器的示例代码
2018/09/13 Javascript
vue-cli 打包使用history模式的后端配置实例
2018/09/20 Javascript
每个 JavaScript 工程师都应懂的33个概念
2018/10/22 Javascript
javascript实现智能手环时间显示
2020/09/18 Javascript
tensorflow入门之训练简单的神经网络方法
2018/02/26 Python
Python实现正整数分解质因数操作示例
2018/08/01 Python
pygame库实现移动底座弹球小游戏
2020/04/14 Python
详解Python 函数参数的拆解
2020/09/02 Python
python 写一个文件分发小程序
2020/12/05 Python
浅析两列自适应布局的3种思路
2016/05/03 HTML / CSS
澳大利亚拥有最好的家具和家居用品在线目的地:Nestz
2019/02/23 全球购物
生物科学专业个人求职信范文
2013/12/05 职场文书
校优秀毕业生主要事迹
2014/05/26 职场文书
我的梦想演讲稿500字
2014/08/21 职场文书
大学生学习面向未来的赶考思想汇报
2014/09/12 职场文书
国家税务局干部作风整顿整改措施
2014/09/18 职场文书
科长个人四风问题整改措施思想汇报
2014/10/13 职场文书
北京英文导游词
2015/02/12 职场文书
班级元旦晚会开幕词
2016/03/04 职场文书
python pyhs2 的安装操作
2021/04/07 Python
浅谈@Value和@Bean的执行顺序问题
2021/06/16 Java/Android
一篇文章带你学习Mybatis-Plus(新手入门)
2021/08/02 Java/Android
「回转企鹅罐」10周年纪念展「輪るピングドラム展」海报公开
2022/03/22 日漫