使用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 相关文章推荐
js获取浏览器的可视区域尺寸的实现代码
Nov 30 Javascript
使用原生js封装webapp滑动效果(惯性滑动、滑动回弹)
May 06 Javascript
基于jQuery实现交互体验社会化分享代码附源码下载
Jan 04 Javascript
bootstrap datepicker 与bootstrapValidator同时使用时选择日期后无法正常触发校验的解决思路
Sep 28 Javascript
Vue.js快速入门实例教程
Oct 15 Javascript
js实现随机抽选效果、随机抽选红色球效果
Jan 13 Javascript
JavaScript 栈的详解及实例代码
Jan 22 Javascript
javascript实现延时显示提示框效果
Jun 01 Javascript
JS判断Android、iOS或浏览器的多种方法(四种方法)
Jun 29 Javascript
vue将时间戳转换成自定义时间格式的方法
Mar 02 Javascript
bootstrap select2插件用ajax来获取和显示数据的实例
Aug 09 Javascript
微信小程序自定义组件的实现方法及自定义组件与页面间的数据传递问题
Oct 09 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
Email+URL的判断和自动转换函数
2006/10/09 PHP
怎样在UNIX系统下安装MySQL
2006/10/09 PHP
PHP array_multisort() 函数的深入解析
2013/06/20 PHP
php分享朋友圈的实现代码
2019/02/18 PHP
javascript iframe中打开文件,并检测iframe存在否
2008/12/28 Javascript
JavaScript调试技巧之console.log()详解
2014/03/19 Javascript
JavaScript实现的圆形浮动标签云效果实例
2015/08/06 Javascript
js仿微博实现统计字符和本地存储功能
2015/12/22 Javascript
JavaScript判断变量是否为数组的方法(Array)
2016/02/24 Javascript
js仿3366小游戏选字游戏
2016/04/14 Javascript
JS实用技巧小结(屏蔽错误、div滚动条设置、背景图片位置等)
2016/06/16 Javascript
Node.js中防止错误导致的进程阻塞的方法
2016/08/11 Javascript
大白话讲解JavaScript的Promise
2017/04/06 Javascript
jQuery自定义元素右键点击事件(实现案例)
2017/04/28 jQuery
JS实现的文字间歇循环滚动效果完整示例
2018/02/13 Javascript
Vue图片浏览组件v-viewer用法分析【支持旋转、缩放、翻转等操作】
2019/11/04 Javascript
JS localStorage存储对象,sessionStorage存储数组对象操作示例
2020/02/15 Javascript
浅谈JSON5解决了JSON的两大痛点
2020/12/14 Javascript
[20:46]Ti4循环赛第三日VG vs DK
2014/07/12 DOTA
[03:00]《DAC最前线》之欧美新秀VS老将
2015/02/01 DOTA
django 修改server端口号的方法
2018/05/14 Python
用pandas中的DataFrame时选取行或列的方法
2018/07/11 Python
使用Python实现在Windows下安装Django
2018/10/17 Python
在Pycharm中设置默认自动换行的方法
2019/01/16 Python
jupyter notebook 添加kernel permission denied的操作
2020/04/21 Python
浅谈TensorFlow中读取图像数据的三种方式
2020/06/30 Python
Django中ORM的基本使用教程
2020/12/22 Python
python中lower函数实现方法及用法讲解
2020/12/23 Python
python3定位并识别图片验证码实现自动登录功能
2021/01/29 Python
意大利会呼吸的鞋:Geox健乐士
2017/02/12 全球购物
请写出 float x 与"零值"比较的 if 语句
2016/01/04 面试题
一道SQL存储过程面试题
2016/10/07 面试题
审计班子对照检查材料
2014/08/27 职场文书
2016党校培训心得体会
2016/01/07 职场文书
python中的class_static的@classmethod的巧妙用法
2021/06/22 Python
2021年国漫热度排行前十,完美世界上榜,第四是美国动画作品
2022/03/18 国漫