requireJs 初识

作者 Simmin 日期 2016-06-21
requireJs 初识

一、前言

文章此次只是对requirejs进行一个初步的学习和总结。

二、What

  1. 非常小巧的JavaScript模块载入框架(模块加载器),只有14K
  2. 基于AMD(Asynchronous Module Definition)规范
  3. 官方地址是:http://www.requirejs.cn/ ,可以到该网址去下载最新的requirejs文件

三、Why

初学JavaScript,我们的代码是这样

<script type="text/javascript">
var a = 1;
var b = 2;
var c = a * a + b * b;
if(c> 1) {
alert('c > 1');
}
function add(a, b) {
return a + b;
}
c = add(a,b);
</script>

这样写看上去也没有什么问题,但对于一个网站的来说,代码的重用性,可维护性是非常重要的。于是我们将零散的代码写成各种函数,甚至封装成类,再引入到页面中。但这样也可能出现一个新的问题:

<script type="text/javascript" src="a.js"></script>
<script type="text/javascript" src="b.js"></script>
<script type="text/javascript" src="c.js"></script>
<script type="text/javascript" src="d.js"></script>
<script type="text/javascript" src="e.js"></script>
<script type="text/javascript" src="f.js"></script>
<script type="text/javascript" src="g.js"></script>
<script type="text/javascript" src="h.js"></script>
<script type="text/javascript" src="i.js"></script>
<script type="text/javascript" src="j.js"></script>

这样就显得页面js引入代码很臃肿,而且不便于处理js文件之间的依赖关系。

requirejs除了可以帮助我们改善上面这两种状况,还可以防止js加载阻塞页面渲染。

有时候,如果我们需要在head中引入js文件:

<html>
<head>
<meta charset="UTF-8">
<title>Document</title>
<script type="text/javascript" src="js/alert.js"></script>
</head>
<body>
<div><h2>This is for test alert.</h2></div>
</body>
</html>
//alert.js
function alertTest(){
alert(123);
}
alertTest();

测试结果(测试浏览器IE):
image

当alert执行时,html内容并未渲染出来,而是点击“确定”之后,html的内容才被渲染。
image

四、How

使用requirejs 必须先引入require.js

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

4.1 普通本地加载

直接加载:

require(["a"]);

带回调函数:

require(["js/a"],function(){
alert("load finished");
})

说明:require API的第一个参数为依赖数组,即使只有一个依赖,也必须使用数组形式。

4.2 外部请求加载

require.config({
paths : {
"jquery" : ["http://libs.baidu.com/jquery/2.0.3/jquery"]
}
})
require(["jquery","js/a"],function($){
$(function(){
alert("load finished");
})
})

先配置,后调用。
require.config 用于配置模块加载路径,并定义模块名字Module ID,方便后续调用。
RequireJS默认假定所有的依赖资源都是js脚本,因此无需在module ID上再加”.js”后缀。同时,路径部分也是以数组形式存在,以确保能够成功引入。

回调函数中参数为依赖模块的输出变量,如上面例子中jquery依赖模块的输出变量$。

4.3 配置requirejs

【1】 全局配置
为了避免每个页面都使用require.config进行配置,requirejs提供了一种叫“主数据”的功能,首先创建一个main.js

require.config({
paths : {
"jquery" : ["http://libs.baidu.com/jquery/2.0.3/jquery", "js/jquery"],
"a" : "js/a"
}
})

然后在页面中以如下方式使用requirejs

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

说明:
①使用data-main属性,这个属性指定的js将在require.js加载完成后执行,每个页面将使用相同的 require.config 配置。
②指定data-main属性后,require会默认将data-main指定的js为根路径。

【2】 require.config

require.config({
baseUrl: "./js",
paths: {
"some": "some/v1"
},
waitSeconds: 15
});

baseUrl :所有模块的查找根路径。
paths :path映射那些不直接放置于baseUrl下的模块名。
waitSeconds :指定最多花多长等待时间来加载一个JavaScript文件,用户不指定的情况下默认为7秒。

更多config的配置参考官方文档:http://www.requirejs.cn/

4.4 定义JavaScript模块

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

具体来说,就是模块必须采用特定的define()函数来定义。如果一个模块不依赖其他模块,那么可以直接定义在define()函数之中。

假定现在有一个math.js文件,它定义了一个math模块。那么,math.js就要这样写:

define(function (){
  var add = function (x,y){
   return x+y;
  };
  return {
    add: add
  };
});

相应的,加载方法是这样:

require(['math'], function (math){
 alert(math.add(1,1));
});

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

define(['myLib'], function(myLib){
 function foo(){
  myLib.doSomething();
 }
 return {
  foo : foo
 };
});

当require()函数加载上面这个模块的时候,就会先加载myLib.js文件。

五、多说几句

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

2.有时候也会看到requirejs.config(),requirejs();其实requirejs === require

3.有时候你想避开”baseUrl + paths”的解析过程,而是直接指定加载某一个目录下的脚本。此时可以这样做:如果一个module ID符合下述规则之一,其ID解析会避开常规的”baseUrl + paths”配置,而是直接将其加载为一个相对于当前HTML文档的脚本:
①以 “.js” 结束.
②以 “/“ 开始.
③包含 URL 协议, 如 “http:” or “https:”.

总结-应用场景

  1. 当一个页面需要加载多个JS文件

  2. 当某一个JS文件需要引入另一个JS文件(非全局引入)

  3. 当某一个JS文件需要依赖另一个JS文件

参考资料

  1. JS模块化工具requirejs教程
  2. Javascript模块化编程(三):require.js的用法