模块化(三):学习require.js

在第一篇文章里面提到,我们在写代码的过程中,难免会遇到要加载很多的js文件,这段代码依次加载多个js文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<title>城市环境监测系统</title>
......//省略css
<script src="js/jquery-1.10.2.min.js" type="text/javascript"></script>
<script src="bootstrap/js/bootstrap.min.js" type="text/javascript" charset="utf-8"></script>
<!-- 用了来显示最上角的数据文件 -->
<script src="API/WSNRTConnect.js" type="text/javascript" charset="utf-8"></script>
<!-- 绘图 -->
<script src="highstock/highstock.js" type="text/javascript" charset="utf-8"></script>
<script src="highstock/modules/exporting.js" type="text/javascript" charset="utf-8"></script>
<!-- 获取历史数据 -->
<script src="API/WSNHistory.js" type="text/javascript" charset="utf-8"></script>
<!-- 调取动态最上角和下拉框数据 -->
<script src="API/history-1.0.min.js" type="text/javascript" charset="utf-8"></script>
<!-- 存放用户密钥之类的信息 -->
<script src="js/config.js" type="text/javascript" charset="gb2312"></script>

加载的文件多并最重要的,它在加载的过程会停止浏览器对网页的渲染,文件与文件直接的关联和依赖也由于js文件增多而变得难以管理。所以便有了require.js

require.js的诞生,就是为了解决这两个问题:
  (1)实现js文件的异步加载,避免网页失去响应;
  (2)管理模块之间的依赖性,便于代码的编写和维护。

如何使用

首先当然是先去官方网站下载,requireJS文件比较小,大约只有14K,所以我们可以手动的将其复制下来。
然后在页面上将其引用。

1
<script src="js/require.js" type="text/javascript"></script>

有人可能会想到,加载这个文件,也可能造成网页失去响应。解决办法有两个:

  1. 把它放在网页底部加载,
  2. 如下
1
<script src="js/require.js" defer async="true" ></script>

async属性表明这个文件需要异步加载,避免网页失去响应。
IE不支持这个属性,只支持defer,所以把defer也写上。

实战

加载require.js以后,下一步就要加载我们自己的代码了。我们需要有个主文件,用来放要加载文件的信息,也可以在里面写你要实现的功能,我们定义主文件为main.js

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

定义了data-main(主模块)之后,加载完requireJS之后就会找到data-main=’main’对应的js,由于require.js默认的文件后缀名是js,所以可以把main.js简写成main,所有代码都从这儿开始运行。(记住,后面所有的文件都不需要加’.js’,否则会报错)

主模块的写法

1.main最简单的测试

1
2
// main.js
alert("加载成功!");

2.加载一个app.js模块

1
2
3
4
// main.js
require(['app'],function(app){
app.initialize();
});
3.加载多个模块
1
2
3
require(['jquery', 'underscore', 'backbone'], function ($, _, Backbone){
    // some code here
});

require()函数接受两个参数。第一个参数是一个数组,表示所依赖的模块,上例就是[‘app’],即主模块依赖这三个模块;第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数形式传入该函数,从而在回调函数内部就可以使用这些模块。

浏览器不会失去响应;它指定的回调函数,只有前面的模块都加载成功后,才会运行,解决了依赖性的问题。

require.js会先加载jQuery、underscore和backbone,然后再运行回调函数。主模块的代码就写在回调函数中。

require.config()方法

我们可以对模块的加载行为进行自定义。require.config()就写在主模块(main.js)的头部。参数就是一个对象,这个对象的paths属性指定各个模块的加载路径。
逐一指定路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
  require.config({
paths:{
jquery :"script/jquery-1.9.1.min",
jqmconfig:'plugin/jqm.config',
jqm:'script/jquery.mobile-1.4.5',
underscore :'script/underscore',
backbone:'script/backbone',
text:'plugin/text.js',
plugin:'plugin',
templates:'templates',
modules:'../'
}
});

直接改变基目录(baseUrl)

1
2
3
4
5
6
require.config({
   baseUrl: "js/lib",
   paths: {
      ...
   }
});

如果某个模块在另一台主机上,也可以直接指定它的网址,比如:

1
2
3
4
5
require.config({
  paths: {
   "jquery": "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min"
  }
});

require.js要求,每个模块是一个单独的js文件。这样的话,如果加载多个模块,就会发出多次HTTP请求,会影响网页的加载速度。因此,require.js提供了一个优化工具,当模块部署完毕以后,可以用这个工具将多个模块合并在一个文件中,减少HTTP请求数。

with AMD

requireJS是采用AMD规范来定义的,所以要安装规范来写代码。AMD规范详情戳
其实就是模块必须采用特定的define()函数来定义。
如果一个模块不依赖其他模块,那么可以直接定义在define()函数之中
假定有一个math.js文件,它定义了一个math模块。那么,math.js就要这样写:

1
2
3
4
5
6
7
8
9
// math.js
define(function (){
  var add = function (x,y){
    return x+y;
  };
  return {
    add: add
  };
});

加载方法如下:

1
2
3
4
// main.js
require(['math'], function (math){
  console.log(math.add(1,1));
});

如果这个模块还依赖其他模块,那么define()函数的第一个参数,必须是一个数组,指明该模块的依赖性

1
2
3
4
5
6
7
8
define(['jquery',"underscore",'backbone',],function($, _, Backbone){
var init = function(){
...
};
return {
initialize:init
}
});

当require()函数加载上面这个模块的时候,就会先加载jquery,underscore,backbone文件。
define([],function(){ }) function里面是加载模块之后的回调函数。

加载非规范的模块

requireJS除了能加载规范化的模块,也可以加载非规范的模块

这样的模块在用require()加载之前,要先用require.config()方法,定义它们的一些特征。
举例来说,underscore和backbone这两个库,都没有采用AMD规范编写。如果要加载它们的话,必须先定义它们的特征。

1
2
3
4
5
6
7
8
9
10
11
require.config({
  shim: {
    'underscore':{
      exports: '_'
    },
    'backbone': {
      deps: ['underscore', 'jquery'],
      exports: 'Backbone'
    }
  }
});

shim属性,专门用来配置不兼容的模块
具体来说,每个模块要定义

  1. exports值(输出的变量名),表明这个模块外部调用时的名称;
  2. deps数组,表明该模块的依赖性。

    比如,jQuery的插件可以这样定义:

    1
    2
    3
    4
    5
    6
    shim: {
      'jquery.scroll': {
        deps: ['jquery'],
        exports: 'jQuery.fn.scroll'
      }
    }

require.js插件

require.js还提供一系列插件,实现一些特定的功能。
domready插件,可以让回调函数在页面DOM结构加载完成后再运行。

1
2
3
require(['domready!'], function (doc){
   // called once the DOM is ready
});

text和image插件,则是允许require.js加载文本和图片文件。

1
2
3
4
5
6
7
8
9
define([
    'text!review.txt',
    'image!cat.jpg'
    ],
    function(review,cat){
      console.log(review);
      document.body.appendChild(cat);
    }
);

类似的插件还有json和mdown,用于加载json文件和markdown文件。

参考资料

阮一峰博客
Require.js 教程

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×