前端开发 HTML5 CSS3 HTML CSS JavaScript jQuery Bootstrap

RequireJS介绍及入门

jQuery HTML我帮您 1年前  0次浏览
如今最常用的JavaScript库之一是RequireJS(http://requirejs.org/)。最近我参与的每个项目,都用到了RequireJS,或者是我向它们推荐了增加RequireJS。在这篇文章中,我将描述RequireJS是什么,以及它的一些基础场景。
异步模块定义(AMD)

谈起RequireJS,你无法绕过提及JavaScript模块是什么,以及AMD是什么。

JavaScript模块只是遵循SRP(Single Responsibility Principle单一职责原则)的代码段,它暴露了一个公开的API。在现今JavaScript开发中,你可以在模块中封装许多功能,而且在大多数项目中,每个模块都有其自己的文件。这使得JavaScript开发者日子有点难过,因为它们需要持续不断的关注模块之间的依赖性,按照一个特定的顺序加载这些模块,否则运行时将会放生错误。

基于 AMD(Asynchronous Module Definition)的 JavaScript 设计已经在目前较为流行的前端框架中大行其道,jQuery、Dojo、MooTools、EmbedJS 等纷纷在其最新版本中加入了对 AMD 的支持。本文介绍的是另一款较为精简的 RequireJS 框架,既想使用 AMD 的特性又不想引入一个庞大的库的开发人员,不妨试试 RequireJS。RequireJS 可以帮助用户异步按需的加载 JavaScript 代码,并解决 JavaScript 模块间的依赖关系,提升了前端代码的整体质量和性能。

前端开发在近一两年发展的非常快,JavaScript 作为主流的开发语言得到了前所未有的热捧。大量的前端框架出现了,这些框架都在尝试着解决一些前端开发中的共性问题,但是实现又不尽相同。在这个背景下,CommonJS 社区诞生了,为了让前端框架发展的更加成熟,CommonJS 鼓励开发人员一起在社区里为一些完成特定功能的框架制定规范。AMD(Asynchronous Module Definition)就是其中的一个规范。
传统 JavaScript 代码的问题

让我们来看看一般情况下 JavaScript 代码是如何开发的:通过


require 方法里的这个字符串数组参数可以允许不同的值,当字符串是以”.js”结尾,或者以”/”开头,或者就是一个 URL 时,RequireJS 会认为用户是在直接加载一个 JavaScript 文件,否则,当字符串是类似”my/module”的时候,它会认为这是一个模块,并且会以用户配置的 baseUrl 和 paths 来加载相应的模块所在的 JavaScript 文件。配置的部分会在稍后详细介绍。

这里要指出的是,RequireJS 默认情况下并没有保证 myFunctionA 和 myFunctionB 一定是在页面加载完成以后执行的,在有需要保证页面加载以后执行脚本时,RequireJS 提供了一个独立的 domReady 模块,需要去 RequireJS 官方网站下载这个模块,它并没有包含在 RequireJS 中。有了 domReady 模块,清单 2 的代码稍做修改加上对 domReady 的依赖就可以了。
清单 3. 页面加载后执行 JavaScript




执行清单 3 的代码后,通过 Firebug 可以看到 RequireJS 会在当前的页面上插入为 a.js 和 b.js 分别声明了一个

使用 RequireJS 来定义 JavaScript 模块

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

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

下面我们先来看一个简单的例子,这个例子通过定义一个 student 模块和一个 class 模块,在主程序中实现创建 student 对象并将 student 对象放到 class 中去。
清单 5. student 模块,student.js

define(function(){
return {
createStudent: function(name, gender){
return {
name: name,
gender: gender
};
}
};
});

清单 6. class 模块,class.js

define(function() {
var allStudents = <>;
return {
classID: "001",
department: "computer",
addToClass: function(student) {
allStudents.push(student);
},
getClassSize: function() {
return allStudents.length;
}
};
}
);

清单 7. 主程序

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 模块,这样主程序部分的逻辑也可以包装进去了。
清单 8. 依赖 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();
}
};
});

清单 9. 新的主程序

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 在其他模块定义时候使用。
清单 10. 载入 require.js



因此,我们前面示例中的所有模块依赖,都可以去掉”js/”,直接写 ”student”, ”class”,”manager” 等。

一种更为直接的方式显示指定 baseUrl 和 paths 就是利用 require.config 来设置这些参数。如清单 11 所示。
清单 11. 配置 RequireJS




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 的官方网站查阅相关文档。

版权所有

发表评论