多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] # 简介 [RequireJS](http://requirejs.org/docs/api.html)是一个工具库,主要用于客户端的模块管理。它可以让客户端的代码分成一个个模块,实现异步或动态加载,从而提高代码的性能和可维护性。它的模块管理遵守AMD规范(Asynchronous Module Definition)。 RequireJS的基本思想是: * 通过define方法,将代码定义为模块; * 通过require方法,实现代码的模块加载。 首先,将require.js嵌入网页,然后就能在网页中进行模块化编程了。 ## 按需加载效果 -- 示例 如果点击了页面,则会有一个脚本`selector.js`进行下载。 **在代码中 `require` 一个文件多次,是否会导致浏览器反复加载? 不会,这是 RequrieJS 的优点,即使你反复 `require` 它,它只加载一次。** ``` require(['jquery', 'event'], function($, E) { $(document).click(function(){ require(['selector'], function (ko) { alert("selector is downloading!!!"); }); alert("selector is Downloaded!!!"); }); }); ``` ## 加载 RequireJS 的方式 方式一: ```html <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 文件。 方式二: ```html <script data-main="js/main" src="scripts/require.js"></script> ``` 则 `data-main` 指定了一个在当前 `index.html` 目录并行的文件夹下的 `/js/main.js` 作为程序入口,而 `/js` 目录也将作为`baseUrl`在其他模块定义时候使用。 用户自定义的代码就放在这个`main.js`文件中。 ## baseUrl ```html <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 秒。 # `require()` 示例: ```js require(['jquery', 'script/hello'],function ($, hello) { $("#btn").click(function(){ hello.showMessage("hangge.com"); }); }); ``` # `define()` ## [定义一个带有名称的模块](http://requirejs.org/docs/api.html#modulename) 你可能会遇到一些第一个参数是有名字的`define()`函数,例如: ```js //Explicitly defines the "foo/title" module: define("foo/title", ["my/cart", "my/inventory"], function(cart, inventory) { //Define foo/title object in here. } ); ``` 这些通常是由优化工具(`r.js`)生成的。您可以自己显式地命名模块,但是**它会使模块的可移植性更低——如果将文件移动到另一个目录,则需要更改其名称**。通常最好避免在模块名称中进行编码,并让优化工具去灌入模块名。优**化工具需要添加名称,以便将多个模块打包在一个文件中,让浏览器更快地加载**。 # 模块的定义 * 模块不同于传统的脚本文件,它良好地定义了一个作用域来避免全局名称空间污染。 * 它可以显式地列出其依赖关系,并以函数(定义此模块的那个函数)参数的形式将这些依赖进行注入,而无需引用全局变量。同时因为无需创建全局变量,甚至可以做到在同一个页面上同时加载同一模块的不同版本。 * RequireJS 的模块语法允许它尽快地加载多个模块,虽然加载的顺序不定,但依赖的顺序最终是正确的。 * 一个js文件应该只定义 1 个模块。**多个模块可以使用内置优化工具将其组织打包**。 ## 模块间的依赖关系 * 模块间的依赖关系如何定义。还是有一些使用技巧需要提示一下: * 尽量不要提供模块的 ID,如 AMD 规范所述,这个 ID 是可选项,如果提供了,在 RequireJS 的实现中会影响模块的可迁移性,文件位置变化会导致需要手动修改该 ID。 * 每个 JavaScript 文件只定义一个模块,模块名称和文件路径的查找算法决定了这种方式是最优的,多个的模块和文件会被优化器进行优化。 * 避免模块的循环依赖,如果实在避免不了,可以模块中加上对`require`模块的依赖,在代码中直接用 `require(”dependencyModuleName”)`。 # 错误处理 1. 全局的错误捕获:`require.onError` 为了捕获在局域的 `errback` 中未捕获的异常,可以重载 `require.onError()` 来实现全局的异常捕获。 ```js require.onError = function (err) { console.log(err.requireType); if (err.requireType === 'timeout') { console.log('modules: ' + err.requireModules); } throw err; }; ``` # 多页面项目使用requireJS [requirejs的入口文件是有且只有一个吗?](http://www.imooc.com/qadetail/52210) 我也有这个疑问,查了github上的资料,对于多个页面的话,`requirejs` 的 `config` 是可以做到多个页面共享的,而每个页面的有自己单独的入口js ,每个入口js首先会加载配置路径的文件,然后再写自己页面的逻辑。 官方示例:https://github.com/requirejs/example-multipage # 参考 [优化网站设计(十七):延迟或按需加载内容](http://www.cnblogs.com/chenxizhang/archive/2013/05/16/3081941.html) [RequireJS - 入门指南、进阶使用详解](http://www.hangge.com/blog/cache/detail_1702.html) [基于gulp requirejs rjs的前端自动化构建系列文章(二)](http://hcysun.me/2015/11/14/基于gulp-requirejs-rjs的前端自动化构建系列文章-二/) https://github.com/ruanyf/jstutorial/blob/gh-pages/tool/requirejs.md