2014年巴西世界杯_田径世界杯 - dutugo.com

require.js - 入门指南、进阶使用详解(附样例)

现在项目大都使用模块化开发,而 RequireJS 作为 AMD 模块开发的典范,还是很值得学习使用的。

目录

一、AMD 规范

1,AMD 基本介绍

2,AMD 模块规范

二、RequireJS 介绍

1,什么是 RequireJS

2,使用 RequireJS 的好处

三、RequireJS 的配置和使用

1,下载最新版的 require.js

2,创建一个如下目录结构

3,效果图

4,代码说明

四、require.configh 函数配置说明

1,baseUrl

2,paths

3,shim

4,map

5,config

五、不同类型的模块定义

1,简单的键值对模块

2,只有一个主函数的模块

3,包含多个函数方法和变量的模块

六 、相对路径的规则

七、循环依赖问题解决

1,什么是循环依赖

2,问题解决

八、错误处理

1,require 的错误回调函数

2,通过"paths"数组配置

3,全局的错误捕获:require.onError

一、AMD 规范

1,AMD 基本介绍

AMD 全称为 Asynchromous Module Definition(异步模块定义) AMD 是 RequireJS 在推广过程中对模块定义的规范化产出,它是一个在浏览器端模块化开发的规范。AMD 模式可以用于浏览器环境并且允许非同步加载模块,同时又能保证正确的顺序,也可以按需动态加载模块。

2,AMD 模块规范

AMD 通过异步加载模块。模块加载不影响后面语句的运行。所有依赖某些模块的语句均放置在回调函数中。AMD 规范只定义了一个函数 define,通过 define 方法定义模块。该函数的描述如下:

define(id?, dependencies?, factory)

id:指定义中模块的名字(可选)。如果没有提供该参数,模块的名字应该默认为模块加载器请求的指定脚本的名字。如果提供了该参数,模块名必须是“顶级”的和绝对的(不允许相对名字)。dependencies:当前模块依赖的,已被模块定义的模块标识的数组字面量(可选)。factory:一个需要进行实例化的函数或者一个对象。

AMD 规范允许输出模块兼容 CommonJS 规范,这时 define 方法如下:

1

2

3

4

5

6

7

8

define(function (require, exports, module) {

var reqModule = require("./someModule");

requModule.test();

exports.asplode = function () {

//someing

}

});

二、RequireJS 介绍

1,什么是 RequireJS

RequireJS 是一个 JavaScript 模块加载器。它非常适合在浏览器中使用,但它也可以用在其他脚本环境, 比如 Rhino 和 Node。使用 RequireJS 加载模块化脚本将提高代码的加载速度和质量。

2,使用 RequireJS 的好处

异步“加载”。使用 RequireJS,会在相关的 js 加载后执行回调函数,这个过程是异步的,所以它不会阻塞页面。按需加载。通过 RequireJS,你可以在需要加载 js 逻辑的时候再加载对应的 js 模块,不需要的模块就不加载,这样避免了在初始化网页的时候发生大量的请求和数据传输。更加方便的模块依赖管理。通过 RequireJS 的机制,你能确保在所有的依赖模块都加载以后再执行相关的文件,所以可以起到依赖管理的作用。更加高效的版本管理。比如原来我们使用的 script 脚本引入的方式来引入一个 jQuery2.x 的文件,但如果有 100 个页面都是这么引用的,如果想换成 jQuery3.x,那你就不得不去改这 100 个页面。而使用 requireJS 只需要改一处地方,即修改 config 中 jQuery 的 path 映射即可。当然还有一些诸如 cdn 加载不到 js 文件,可以请求本地文件等其它的优点,这里就不一一列举了。

三、RequireJS 的配置和使用

1,下载最新版的 require.js

下载地址:http://requirejs.org/docs/download.html

2,创建一个如下目录结构

(1)lib 文件夹下放置一些需要用到的 js 库,这里除了 require.js 外,还有 jquery。

(2)script 文件夹下放置 RequireJS 的入口 js、以及模块 js 文件。

(3)index.html 则为主页面。

3,效果图

(1)页面初始化的时候显示一个按钮。

(2)点击按钮会调用 hello 模块的方法,将信息显示在页面上。

4,代码说明

(1)index.html

1

2

3

4

5

6

7

8

9

10

11

12

hangge.com

注意 script 标签,除了指定 require.js 路径外,还有个 data-main 属性: 这属性指定在加载完 reuqire.js 后,就用 requireJS 加载该属性值指定路径下的 JS 文件并运行,所以一般该 JS 文件称为主 JS 文件(其 .js 后缀可以省略)。

(2)main.js

1

2

3

4

5

6

7

8

9

10

11

12

require.config({

baseUrl: 'js',

paths: {

jquery: 'lib/jquery-1.11.1',

}

});

require(['jquery', 'script/hello'],function ($, hello) {

$("#btn").click(function(){

hello.showMessage("hangge.com");

});

});

要改变 RequireJS 的默认配置,可以使用 require.configh 函数传入一个可选参数对象。下面是一些可以使用的配置:

baseUrl:用于加载模块的根路径。在配置这个属性后,以后的文件都是在这个路径下查找内容了。paths:用于一些常用库或者文件夹路径映射,方便后面使用,省得每次都要输入一长串路径。(js 文件的后缀可以省略)shim:加载非 AMD 规范的 js,并解决其载入顺序。

require方法:

require 函数用于加载模块依赖,这里我们加载了 jQuery 以及 hello 这个自定义模块。在加载完毕的回调中,给按钮添加个点击事件,同时点击后会调用 hello 模块中的 showMessage 方法。

(3)hello.js

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

define(['jquery'],function($){

//变量定义区

var moduleName = "hello module";

var moduleVersion = "1.0";

//函数定义区

var showMessage = function(name){

if(undefined === name){

return;

}else{

$('#messageBox').html('欢迎访问 ' + name);

}

};

//暴露(返回)本模块API

return {

"moduleName":moduleName,

"version": moduleVersion,

"showMessage": showMessage

}

});

我们通过 define 方法定义一个 js 模块,并通过 return 对外暴露出接口(两个属性,一个方法)。同时该模块也是依赖于 jQuery。

四、require.configh 函数配置说明

要改变 RequireJS 的默认配置,可以使用 require.configh 函数传入一个可选参数对象。上面只演示了其中 baseUrl 和 paths 这两个配置,下面是一个完整的配置:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

require.config({

baseUrl: 'js',

paths: {

jquery: 'lib/jquery-1.11.1'

},

shim: {

'backbone': {

deps: ['underscore', 'jquery'],

exports: 'Backbone'

},

'underscore': {

exports: '_'

},

'modal':{//模态框插件不是模块化

deps:['jquery'],

export:"modal"

},

},

map: {

'script/newmodule': {

'foo': 'foo1.2'

},

'script/oldmodule': {

'foo': 'foo1.0'

}

},

config: {

'script/bar': {

size: 'large'

},

'script/baz': {

color: 'blue'

}

}

});

1,baseUrl

用于加载模块的根路径。在配置这个属性后,以后的文件都是在这个路径下查找内容了。

2,paths

用于一些常用库或者文件夹路径映射,方便后面使用,省得每次都要输入一长串路径。(js 文件的后缀可以省略)

3,shim

虽然目前已经有一部分流行的函数库(比如 jQuery)符合 AMD 规范,但还有很多库并不符合。shim 就是为了加载这些非 AMD 规范的 js,并解决其载入顺序的。

比如上面样例,我们想通过 RequireJS 来使用 backbone,那么你就需要在配置中把它定义为一个 shim。同时通过 deps 配置其依赖关系,可以保证 underscore、jquery 先被加载。

shim配置的注意事项:

shim 配置仅设置了代码的依赖关系,想要实际加载 shim 指定的或涉及的模块,仍然需要一个常规的 require/define 调用。设置 shim 本身不会触发代码的加载。请仅使用其他"shim"模块作为 shim 脚本的依赖,或那些没有依赖关系,并且在调用 define() 之前定义了全局变量(如 jQuery 或 lodash )的 AMD 库。否则,如果你使用了一个 AMD 模块作为一个 shim 配置模块的依赖,在 build 之后,AMD 模块可能在 shim 托管代码执行之前都不会被执行,这会导致错误。终极的解决方案是将所有 shim 托管代码都升级为含有可选的 AMD define() 调用。

4,map

(1)对于给定的模块前缀,使用一个不同的模块 ID 来加载该模块。该手段对于某些大型项目很重要。

比如上面配置以后,不同的模块会使用不同版本的"foo":

当 some/newmodule 调用了 require('foo'),它将获取到 foo1.2.js 文件。当 some/oldmodule 调用 require('foo'),时它将获取到 foo1.0.js 文件。

(2)map 还支持“*”,意思是“对于所有的模块加载,使用本 map 配置”。如果还有更细化的 map 配置,会优先于“*”配置。

比如下面配置,除了“some/oldmodule”外的所有模块,当要用“foo”时,都使用“foo1.2”来替代。

1

2

3

4

5

6

7

8

9

10

requirejs.config({

map: {

'*': {

'foo': 'foo1.2'

},

'some/oldmodule': {

'foo': 'foo1.0'

}

}

});

5,config

我们需要将配置信息传给一个模块。这些配置往往是 application 级别的信息,需要一个手段将它们向下传递给模块。这个通过 requirejs.config() 的 config 配置项就可以实现。

(1)可以通过加载特殊的依赖“module”来获取这些信息。

1

2

3

4

5

// script/info.js

define(['module'], function (module) {

var color = module.config().color; //blue

});

(2)也可通过符合 CommonJS 规范的模块获取

1

2

3

4

5

// script/info.js

define(function (require, exports, module) {

var color = module.config().color; //blue

});

五、不同类型的模块定义

模块不同于传统的脚本文件,它良好地定义了一个作用域来避免全局名称空间污染。它可以显式地列出其依赖关系,并以函数(定义此模块的那个函数)参数的形式将这些依赖进行注入,而无需引用全局变量。同时因为无需创建全局变量,甚至可以做到在同一个页面上同时加载同一模块的不同版本。RequireJS 的模块语法允许它尽快地加载多个模块,虽然加载的顺序不定,但依赖的顺序最终是正确的。一个磁盘文件应该只定义 1 个模块。多个模块可以使用内置优化工具将其组织打包。

1,简单的键值对模块

(1)如果一个模块仅含键值对,没有任何依赖,则在 define() 中定义这些值对就好了

1

2

3

4

5

// script/shirt.js

define({

color: "black",

size: "unisize"

});

下面调用并测试这个模块

1

2

3

require(['script/shirt'],function (shirt) {

console.log("颜色:" + shirt.color);

});

(2)下面还是一个简单的键值对模块,没有任何依赖,但需要做一些初始化 setup 工作。

1

2

3

4

5

6

7

8

9

10

// script/shirt.js

define(function () {

//在这里做一些setup工作

console.log("Do setup work here...");

return {

color: "black",

size: "unisize"

}

});

2,只有一个主函数的模块

(1)没有任何依赖

1

2

3

4

5

6

// script/info.js

define(function () {

return function (){

alert("欢迎访问 hangge.com");

};

});

下面调用并测试这个模块:

1

2

3

require(['script/info'],function (info) {

info();

});

(2)存在相关依赖

1

2

3

4

5

6

// script/info.js

define(['jquery'],function($){

return function (){

$('#messageBox').html('欢迎访问 hangge.com');

};

});

下面调用并测试这个模块:

1

2

3

require(['script/info'],function (info) {

info();

});

3,包含多个函数方法和变量的模块

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

// script/hello.js

define(['jquery'],function($){

//变量定义区

var moduleName = "hello module";

var moduleVersion = "1.0";

//函数定义区

var showMessage = function(name){

if(undefined === name){

return;

}else{

$('#messageBox').html('欢迎访问 ' + name);

}

};

//暴露(返回)本模块API

return {

"moduleName":moduleName,

"version": moduleVersion,

"showMessage": showMessage

}

});

下面调用并测试这个模块:

1

2

3

4

5

require(['jquery', 'script/hello'],function ($, hello) {

$("#btn").click(function(){

hello.showMessage("hangge.com");

});

});

六 、相对路径的规则

不管是在配置中写路径还是直接在 require 函数中写路径,我们需要了解 requireJS 在不同情况下的相对路径。以下是相对路径的规则:

如果