require.js API:http://requirejs.org/docs/api.html#config
参考文档:http://www.tuicool.com/articles/bu6Zbi
require.js优点
1.实现JS文件的异步加载,避免网页被堵塞
2.管理模块之间的依赖性,便于代码的编写和维护
基本语法及使用
1.引用require.js
在页面头部head标签内引用require.js,如下:
<script src="js/require.js"></script>
但是这个加载这个文件也可能造成网页失去响应,也是同步加载,我们可以加上defer和async属性,如下:
<script src="js/require.js" defer async="true"></script>
Asynce属性表明文件需要异步加载,IE不支持这个属性,值支持defer,所以上面把这两个属性都加上。接下来,看看require.js启动加载脚本的初始化方式,requireJS支持属性data-main这个属性来加载初始化的js文件,如下:
<script src="js/require.js" defer async="true" data-main="js/app.js"></script>
上面的意思是:先异步加载require.js文件,完成后继续异步加载app.js文件,上面app.js后的.js可以去掉,require.js默认后缀名是.js
2.定义模块文件
require.js编写模块不同于其他脚本文件,它良好的使用define来定义一个作用域避免污染全局空间,它可以显示出其依赖关系,并以函数(模块定义中的那个函数)参数的形式将这些依赖注入
做一个demo,新建如下一个项目文件:
现在app/b.js中添加模块定义代码:
define(function(){ var add = function(x,y){ return x + y; }; return{ add:add } });
使用define定义模块,下面我们需要在app.js里面加载b.js模块,代码如下:
require(['app/b'],function(b){ console.log(b.add(1,1)); });
在head标签内动态生成文件,如下:
<head> <meta charset="UTF-8"> <title>Insert title here</title> <script src="js/require.js" defer="" async="true" data-main="js/app"></script> <script> </script> <script type="text/javascript" charset="utf-8" async="" data-requirecontext="_" data-requiremodule="app" src="js/app.js"></script> <script type="text/javascript" charset="utf-8" async="" data-requirecontext="_" data-requiremodule="app/b" src="js/app/b.js"></script> </head>
可以看到加载顺序是require.js-->app.js-->b.js
上面是使用define定义一个函数,我们可以直接定义一个对象(可以解决污染全局变量的问题,关于define更多内容请看《AMD》一文),现在在a.js中定义一个对象:
define({ name:'jiaqing', age:22 });
app.js初始化代码改为:
require(['app/a'],function(a){ console.log(a); )};
结果可以自己测试下
3.AMD模块定义规范
①:
define(function(){ return x:x });
②有依赖项:
define(['data'],function(data){ });
③定义对象:
define({ data:''; ui:''; });
④具名模块:
define('index',['data'],function(data){ //todo });
⑤包装模块:
define(function(require,exports,module){ var base = require('base'); //这一句相当于define的模块依赖id为‘base’的模块 exports.show = function(){ //todo with module base } //exports.show这句相当于 return {show:} });
这个书写格式和node.js比较像,可以使用require获取模块依赖,使用exports或者module.exports导出API
更多AMD的细节参见《AMD》一文,require.js很好的实现了AMD规范,所以也有上面的定义模块方式
举个例子理解第五种写法,想引用a.js,修改app.js代码如下:
define(function(require,exports,module){ var a = require('app/a'); console.log(a); exports.show = function(){ } });
注意:1.书写require.js遵循一个文件一个模块
2.不要手动写模块名标识
4.require.js配置项
1.baseUrl:指定本地模块的基准目录,即本地模块的路径是相对于哪个目录的,该属性通常由require.js加载时的data-main属性指定。
项目结构还是上面的,在index.html页面<head>中引用 <script src="js/require.js" defer async="true" data-main="js/app"></script>
在app.js中写如下代码:
require.config({ baseUrl:'js/app' }); require(['a','b','c'],function(a,b,c){ });
看项目文件图,index.html和js目录是同一个目录下的,都是放在require文件夹里面的,所以定义baseUrl:‘js/app’会自动解析成require/js/app/ 所以require(['a','b','c'])的话,会自动到require/js/app/目录下去查找a.js,b.js,c.js,找到了就可以加载出来
如果未显式设置baseUrl,则默认值是加载require.js的html所处的位置,如果使用了data-main属性的话,则该路径成了baseUrl。
如果把上面app.js中的require.config去掉则对‘a’,‘b’,‘c’的引用在浏览器中被解析成:
<head> <meta charset="UTF-8"> <title>Insert title here</title> <script src="js/require.js" defer="" async="true" data-main="js/app"></script> <script> </script> <script type="text/javascript" charset="utf-8" async="" data-requirecontext="_" data-requiremodule="app" src="js/app.js"></script> <script type="text/javascript" charset="utf-8" async="" data-requirecontext="_" data-requiremodule="a" src="js/a.js"></script> <script type="text/javascript" charset="utf-8" async="" data-requirecontext="_" data-requiremodule="b" src="js/b.js"></script> <script type="text/javascript" charset="utf-8" async="" data-requirecontext="_" data-requiremodule="c" src="js/c.js"></script> </head>
也就是在app.js所在的js目录下查找他们
2.paths:为那些模块名称没有直接存在baseUrl内的模块做路径映射,设置paths的起始位置是相对于baseUrl的,除非该path设置是以“/”开头或含有URL协议(http://或https://)
模块名称对应的路径名不应该包含扩展名,因为路径名也可以用于映射目录,如果映射的是模块,将会自动加上.js扩展名
例子:
将上面app.js代码改为:
require.config({ baseUrl:'js/lib', paths:{ app:'../app' } }); require(['app/a'],function(a){ });
则页面加载显示如下:
<head> <meta charset="UTF-8"> <title>Insert title here</title> <script src="js/require.js" defer="" async="true" data-main="js/app"></script> <script> </script> <script type="text/javascript" charset="utf-8" async="" data-requirecontext="_" data-requiremodule="app" src="js/app.js"></script> <script type="text/javascript" charset="utf-8" async="" data-requirecontext="_" data-requiremodule="app/a" src="js/lib/../app/a.js"></script> </head>
可以看到paths是相对于baseUrl配置项生成的,'..'解析到上层的js目录。require(['app/a'])实际上就是解析到js/app/a.js了。
3.shim:为旧的,传统的且没有使用define()声明依赖和模块值的“浏览器全局”脚本配置依赖,输出值和用户初始化
4.其他配置属性看文档
5.内部机制
require.js加载每个模块作为scriptTag,使用head.appendChild()方法,在模块定义时,require.js等到所有的依赖都加载完毕,会为函数的调用计算出正确的顺序,然后在函数中通过正确的顺序进行调用