一、认识require.js:javascript
官方文档:http://requirejs.org/
RequireJS是一个很是小巧的JavaScript模块载入框架,是AMD规范最好的实现者之一。最新版本的RequireJS压缩后只有14K,堪称很是轻量。它还同时能够和其余的框架协同工做,使用RequireJS必将使您的前端代码质量得以提高。
RequireJS 是一个JavaScript模块加载器。它很是适合在浏览器中使用, 但它也能够用在其余脚本环境, 就像 Rhino and Node. 使用RequireJS加载模块化脚本将提升代码的加载速度和质量。html
二、require.js的优势:前端
<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>java
三、在网页中未使用require.js和使用require.js比较jquery
网页中未使用require.js编写方式:编程
index.html:api
<!DOCTYPE html> <html> <head> <script type="text/javascript" src="a.js"></script> </head> <body> <span>body</span> </body> </html>
a.js:数组
function fun1(){ alert("it works"); } fun1();
可能你更喜欢这样写:浏览器
a.js:服务器
(function(){ function fun1(){ alert("it works"); } fun1(); })()
第二种方法使用了块做用域来申明function防止污染全局变量,本质仍是同样的,当运行上面两种例子时不知道你是否注意到,alert执行的时候,html内容是一片空白的,即<span>body</span>并未被显示,当点击肯定后,才出现,这就是JS阻塞浏览器渲染致使的结果。
使用require.js写法:
index.html
<!DOCTYPE html> <html> <head> <script type="text/javascript" src="require.js"></script> <script type="text/javascript"> require(["a"]); </script> </head> <body> <span>body</span> </body> </html>
a.js
define(function(){ function fun1(){ alert("it works"); } fun1(); })
浏览器提示了"it works",说明运行正确,可是有一点不同,此次浏览器并非一片空白,body已经出如今页面中。
四、熟悉requirejs基本API
require会定义三个变量:define,require,requirejs,其中require === requirejs,通常使用require更简短;
一个回调函数:callback
用define定义模块的方法以下:【function定义法】
若是index.html,main.js,js文件夹为平级目录,a.js和jquery.js位于js文件夹下,
a.js【AMD规范的写法】
define(function() { var target = null; function countTool() { target = this; target.value = 0; }; countTool.prototype.add = function(a, b) { return a + b; }; countTool.prototype.minus = function(a, b) { return a - b; }; return countTool; });
用require 加载依赖模块,没有用到callback回调函数,方法以下:
main.js
require(["js/a"]);
来加载该模块(注意require中的依赖是一个数组,即便只有一个依赖,你也必须使用数组来定义).
require API的第二个参数是callback,一个function,是用来处理加载完毕后的逻辑,如:
main.js
require(["js/a"],function(countTool){ countTool.add(2,3); })
会获得结果为:5
如上的写法,咱们发现require()第一个数组的参数中,添加的a.js的写法["js/a"]较繁琐。但可使用require.config()来进行优化。
五、用require.config()来加载文件
以前的例子中加载模块都是本地js,可是大部分状况下网页须要加载的JS可能来自本地服务器、其余网站或CDN,这样就不能经过这种方式来加载了,咱们以加载一个jquery库为例:
main.js
require.config({ paths : { "jquery" : ["http://libs.baidu.com/jquery/2.0.3/jquery"], // paths还能够配置多个路径,若是远程cdn库没有加载成功,能够加载本地的库,以下: // "jquery" : ["http://libs.baidu.com/jquery/2.0.3/jquery", "js/jquery"], "a" : "js/a" } }) require(["jquery","a"],function($,a){ $(function(){ a.add(2,3); // 5 }) })
在使用requirejs时,加载模块时不用写.js后缀的,固然也是不能写后缀
六、requirejs的使用方法
<script data-main="js/main" src="js/require.js" defer async="true"></script>
相关参数解析以下:
(1)、加载requirejs脚本的script标签加入了data-main属性,是指当reuqire.js加载完成以后,就可使用这个配置文件(main.js)来直接使用require来加载全部的短模块名。
(2)、当script标签指定data-main属性时,require会默认的将data-main指定的js为根路径,是什么意思呢?如上面的data-main="js/main"设定后,咱们在使用require(['jquery'])后(不配置jquery的paths),require会自动加载js/jquery.js这个文件,而不是jquery.js,至关于默认配置了:
require.config({ baseUrl : "js" })
(3)、async属性代表这个文件须要异步加载,避免网页失去响应。
(4)、IE的异步加载,只支持defer,因此把defer也写上。
注意:前提是须要在js/libs文件夹下放入jquery.js和a.js,而且a.js要实现AMD规范的写法,参照上面的a.js.
main.js
require.config({ paths : { "jquery" : "./libs/js/jquery", "a" : ".libs/js/a" } }) require(["jquery","a"],function($,a){ console.log($); a.add(2,3); // 5 })
另一种优化paths的方法为:使用参数baseUrl,前提是js/jquery.js,js/a.js以下:另一种优化paths的方法为:使用参数baseUrl,前提是js/jquery.js,js/a.js以下:
main.js
require.config({ baseUrl: "js/lib", paths: { "jquery": "jquery", "a": "a" } }); require(["jquery","a"],function($,a){ console.log($); a.add(2,3); // 5 })
require.js加载的模块,采用AMD规范。也就是说,模块必须按照AMD的规定来写。
具体来讲,就是模块必须采用特定的define()函数来定义。若是一个模块不依赖其余模块,那么能够直接定义在define()函数之中。
require定义一个模块是经过 define = function (name, deps, callback)完成的,第一个参数是定义模块名,第二个参数是传入定义模块所须要的依赖,第三个函数则是定义模块的主函数,主函数和require的回调函数同样,一样是在依赖加载完之后再调用执行。
以下,没有依赖模块的写法。假定如今有一个a.js文件,它定义了一个a模块。那么,a.js就要这样写:
a.js 写法一: 直接定义方法
define(function (){ // 加法 var add = function (x,y){ return x+y; }; // 减法 var minus = function(x,y){ return x-y; } return { add: add, minus:minus }; });
a.js 写法二: 方法衍生法
define(function() { var target = null; function countTool() { target = this; target.value = 0; }; countTool.prototype.add = function(a, b) { return a + b; }; countTool.prototype.minus = function(a, b) { return a - b; }; return countTool; });
a.js 写法三: 对象定义法
define(function() { var module = {}; module.value = 0; //加法 var add = function(a, b) { return a + b; } //减法 var minus = function(a, b) { return a - b; } module.add = add; module.minus = minus; return module; });
加载方法以下:
main.js
require(['a'], function (a){ alert(a.add(1,1)); // 2 });
若是这个模块还依赖其余模块,那么define()函数的第一个参数,必须是一个数组,指明该模块的依赖性。
依赖对象定义,如: b.js,假设b.js中定义乘法和除法方法。
define(['./b'], function(b) { var module = {}; var add = a.add; //加法 var minus = a.minus; //减法 var multi = b.multi; // 乘法 var division = b.division; // 除法 module.add = add; module.minus = minus; module.multi = multi ; module.division = division; return module; });
当require()函数加载上面这个模块的时候,就会先加载a.js文件。
为何我始终都没有使用name来定义本身的模块名:
若是你细心,你可能会发现,刚刚define函数,有一个参数name是用来定义模块名的(也就是第一个传参),为何上面两个例子都没有用到。其实我确实能够添加模块名,以下:
define('b',['./b'],function(b){ ..... })
可是,这样作感受不颇有必要,由于若是哪一天我将这个文件转移到其余目录下,那我就得在这这里再修改一次模块名。官方其实也不推荐,用官方的说法是:让优化工具去自动生成这些模块名吧!
理论上,require.js加载的模块,必须是按照AMD规范、用define()函数定义的模块。可是实际上,虽然已经有一部分流行的函数库(好比jQuery)符合AMD规范,更多的库并不符合。那么,require.js是否可以加载非规范的模块呢?
回答是能够的。
那么如何判断一个js库,有没有采用AMD规范?只需看其js库中,有没有实现define.amd相关的判断代码便可;
如jQuery中实现AMD的代码以下:
if ( typeof define === "function" && define.amd ) { define( "jquery", [], function() { return jQuery; } ); }
underscore.js v1.6中AMD的代码以下:
if (typeof define === 'function' && define.amd) { define('underscore', [], function() { return _; }); }
jQuery 从 1.7 版本开始支持了 AMD 对其类库的加载,因此开发者能够经过 require 方法来异步加载 jQuery 的源代码。
underscore.js从1.6,backbone.js从1.1.1版本以后开始支持了 AMD 对其类库的加载;
例如,若是用到underscore.js v1.6或者backbone.js v1.1.1以前的版本,这样的模块在用require()加载以前,要先用require.config()方法,定义它们的一些特征。这里须要用到shim{},专门用来配置不兼容的模块,以下:
require.config({ shim: { 'underscore':{ exports: '_' }, 'backbone': { deps: ['underscore', 'jquery'], exports: 'Backbone' }, 'jquery.scroll': { deps: ['jquery'], exports: 'jQuery.fn.scroll' } } });
如:dateUtil.js,没有用define()来定义。
(function(window) { var DateUtils = {}; DateUtils.toString = function() { alert("toString"); }; // 全局变量 window.DateUtils = DateUtils; })(window);
加载该模块的方法以下:
require.config({ shim:{ dateUtil:{ deps:[], exports:'dateUtil' } } });
具体来讲,每一个模块要定义
(1)deps数组,代表该模块的依赖性。
(2)exports值(输出的变量名),代表这个模块外部调用时的名称;
七、require.js提供了一个优化工具r.js
require.js提供了一个优化工具r.js或者到网盘下载,当模块部署完毕之后,能够用这个工具将多个模块合并在一个文件中,减小HTTP请求数。
具体使用方法,请参考下节:require.js实现js模块化编程(二):RequireJS Optimizer
八、相关文档:
require.js,实现具体的项目构建,请自行下载,谢谢关注。