Require.JS解决的问题:
RequireJS的基本思想:通过define方法,将代码定义为模块;通过require方法,实现代码的模块加载。
一 采用AMD规范编写模块
1.采用define()函数来定义模块
@1.模块不依赖其他模块,直接定义在define()函数之中
简写:生成一个拥有method1method2两个方法的模块
define({
method1: function(){},
method2:function(){},
})
另一种等价的写法是,把对象写成一个函数,该函数的返回值就是输出的模块
define(function(){
return{
method1:function(){},
method2:function(){},
};
})
后一种写法的自由度更高一点,可以在函数体内写一些模块初始化代码
字面量写法:
define(function (){
var add = function (x,y){
return x+y;
};
return {
add: add 前面的add对应外部调用名 后面的add对应模块里的实现函数名
};
});
@2.非独立模块:模块还依赖其他模块
如果这个模块还依赖其他模块,那么define()函数的第一个参数,必须是一个数组,指明该模块的依赖性。
define(['module1','module2'],function(m1,m2)){
.......doSomething
}
define方法的第一个参数是一个数组,它的成员是当前模块所依赖的模块。比如,['module1', 'module2']表示我们定义的这个新模块依赖于module1模块和module2模块,只有先加载这两个模块,新模块才能正常运行。一般情况下,module1模块和module2模块指的是,当前目录下的module1.js文件和module2.js文件,等同于写成['./module1', './module2']。
define方法的第二个参数是一个函数,当前面数组的所有成员加载成功后,它将被调用。它的参数与数组的成员一一对应,比如function(m1, m2)就表示,这个函数的第一个参数m1对应module1模块,第二个参数m2对应module2模块。
这个函数必须返回一个对象,供其他模块调用。
define(['module1', 'module2'], function(m1, m2) {
return {
method: function() {
m1.methodA();
m2.methodB();
}
};
});
上面代码表示新模块返回一个对象,该对象的method方法就是外部调用的接口,menthod方法内部调用了m1模块的methodA方法和m2模块的methodB方法。
需要注意的是,回调函数必须返回一个对象,这个对象就是你定义的模块。
define(['myLib'], function(myLib){
function foo(){
myLib.doSomething();
}
return {
foo : foo
};
});
当require()函数加载上面这个模块的时候,就会先加载myLib.js文件
二 模块调用
1. 加载require.js将require.js嵌入网页
<script src="js/require.js" defer async="true" ></script>
async属性表明这个文件需要异步加载,避免网页失去响应。IE不支持这个属性,只支持defer,所以把defer也写上
2. 加载主模块:整个网页的入口代码
加载require.js以后,下一步就要加载我们自己的代码了。假定我们自己的代码文件是main.js,也放在js目录下面。
<script data-main="scripts/main" src=" js /require.js"></script>
data-main属性不可省略,用于指定网页程序的主模块,在上例中为js子目录下的main.js文件,这个文件会第一个被require.js加载。由于require.js默认的文件后缀名是js,所以可以把main.js简写成main。
3. 编写主模块
常见的情况是,主模块依赖于其他模块,这时就要使用AMD规范定义的的require()函数。
require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){
// some code here
});
require()函数接受两个参数。
第一个参数是一个数组,表示所依赖的模块,上例就是['moduleA', 'moduleB', 'moduleC'],即主模块依赖这三个模块;
第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数形式传入该函数,从而在回调函数内部就可以使用这些模块。
require()异步加载moduleA,moduleB和moduleC,浏览器不会失去响应;它指定的回调函数,只有前面的模块都加载成功后,才会运行,解决了依赖性的问题。
默认情况下,require.js假定这三个模块与main.js在同一个目录,文件名分别为jquery.js,underscore.js和backbone.js,然后自动加载。
require(['foo', 'bar'], function ( foo, bar ) {
foo.doSomething();
});
上面方法表示加载foo和bar两个模块,当这两个模块都加载成功后,执行一个回调函数。该回调函数就用来完成具体的任务。
require方法的第一个参数,是一个表示依赖关系的数组。这个数组可以写得很灵活,请看下面的例子。
require( [ window.JSON ? undefined : 'util/json2' ], function ( JSON ) {
JSON = JSON || window.JSON;
console.log( JSON.parse( '{ "JSON" : "HERE" }' ) );
});
上面代码加载JSON模块时,首先判断浏览器是否原生支持JSON对象。如果是的,则将undefined传入回调函数,否则加载util目录下的json2模块。
如何动态加载模块
define(function ( require ) {
var isReady = false, foobar;
require(['foo', 'bar'], function (foo, bar) {
isReady = true;
foobar = foo() + bar();
});
4.模块加载 require.config()方法
require.config()方法,我们可以对模块的加载行为进行自定义。
require.config()就写在主模块(main.js)的头部。参数就是一个对象,这个对象的paths属性指定各个模块的加载路径。
@1.路径默认与main.js在同一个目录
require.config({
paths: {
"jquery": "jquery.min",
"underscore": "underscore.min",
"backbone": "backbone.min"
}
});
@2.逐一指定路径 (js/lib)
require.config({
paths: {
"jquery": "lib/jquery.min",
"underscore": "lib/underscore.min",
"backbone": "lib/backbone.min"
}
});
@3.设置基路径 baseUrl
require.config({
baseUrl: "js/lib",
paths: {
"jquery": "jquery.min",
"underscore": "underscore.min",
"backbone": "backbone.min"
}
});
require.js要求,每个模块是一个单独的js文件。这样的话,如果加载多个模块,就会发出多次HTTP请求,会影响网页的加载速度。因此,require.js提供了一个优化工具,当模块部署完毕以后,可以用这个工具将多个模块合并在一个文件中,减少HTTP请求数。
return {
isReady: isReady,
foobar: foobar
};
});
上面代码所定义的模块,内部加载了foo和bar两个模块,在没有加载完成前,isReady属性值为false,加载完成后就变成了true。因此,可以根据isReady属性的值,决定下一步的动作。
2.domready插件,可以让回调函数在页面DOM结构加载完成后再运行。
require(['domready!'], function (doc){
// called once the DOM is ready
});