转自:http://home.cnblogs.com/u/snandy/css
1、node
加载JavaScript文件:
RequireJS的目标是鼓励代码的模块,它使用不一样于传统<script>标签的脚本加载步骤。
能够用它来加速、优化代码,但其主要目的仍是为了代码的模块化,它鼓励在使用脚本时以
module ID替代URL地址
RequireJS以一个相对于baseUrl的地址来加载全部的代码,页面顶层<script>标签含有一个特殊
的属性data-main,require.js使用他来启动脚本加载过程,而baseUrl通常设置到与该属性相一致
的目录,下列示例中展现baseUrl的设置:
<script data-main="scripts/main.js" src="scripts/require.js"></script>
baseUrl亦可经过RequireJS config手动设置,若是没有显示指定config及data-main,则默认的baseUrl
为包含RequireJS的那个HTML页面的所属目录。
RequireJS默认全部的依赖资源都是js脚本,所以无需在module ID上再添加“.js”后缀
RequireJS在进行moduleID到path的解析时会自动补上后缀,你能够经过paths config设置一组脚本,
这是有助于咱们在使用脚本时码更少的字
有时候你想避开“baseUrl+paths”的解析过程,而是直接指定加载某一个目录下的脚本,此时能够这样作:
若是一个module ID符合下述规则之一,其ID解析会避开常规的“baseUrl+paths”配置,而是直接将其加载为
一个相对于当前HTML文档的脚本:
·以“.js”结束
·以“/”开始
·包含URL协议,如“http:”or“https:”
通常来讲,最好仍是使用baseUrl及“paths” config去设置module ID。它会给你带来额外的灵活性,
如便于脚本的重命名、重定位等。同时,为了不凌乱的配置,最好不要使用多级嵌套的目录层次来
组织代码,而是要么将全部的脚本都放置到baseUrl中,要么分置为项目库/第三方库的一个扁平结构,以下:jquery
注意在示例中,三方库jQuery没有将版本号包含在他们的文件夹中。咱们建议将版本信息放置在单独的文件中来
进行跟踪。使用诸如volo这类的工具,能够将package.json打上版本信息,并在磁盘上保持文件名为‘jquery.js’
这有助于你保持配置的最小化,避免为每一个库版本设置一条path,例如,将‘jquery’配置为“jquery-1.7.2”ajax
理想情况下,每一个加载的脚本都是经过define()来定义的一个模块;但有些“浏览器全局变量注入”型的传统/遗留库
并无使用define()来定义它们的依赖关系,你必须为此使用shim config来指明它们的依赖关系,若是你没有
指明依赖关系,加载可能报错,这是由于基于速度的缘由,RequireJS会异步地以无序的形式加载这些库json
data-main入口点:
require.js在加载的时候会检查data-main属性:
<script data-main="scripts/main" src="scripts/require.js"></script>
你能够在啊data-main指向的脚本中设置模块加载选项,而后加载第一个应用模块。注意:你在main.js中所设置
的脚本是异步加载的,因此若是你在页面中配置了其余JS加载,则不能保证它们所依赖的JS已经加载成功api
例如:
<script data-main="scripts/main" src="scripts/require.js"></script>
<script src="scripts/other.js"></script>数组
//contents of main.js:
require.config({
paths : {
foo : 'libs/foo-1.1.3'
}
})浏览器
//contents of other.js:
//This code might be called before the require.config() in main.js
//has executed When that happens, require.js will attempt to
//load 'scripts/foo.js' instead of 'scripts/libs/foo-1.1.3.js'
require(['foo'],function(foo){
});安全
定义模块:
模块不一样于传统的脚本文件,他良好的定义了一个做用域来避免全局名称空间污染,它能够显式
地列出其依赖关系,并以函数(定义此模块的那个函数)参数的形式将这些依赖进行注入,而无需
引用全局变量,Require.js的模块是模块模式的一个扩展,其好处是无需全局地引用其余模块
require.js的模块语法容许它尽快地加载多个模块,虽然加载的顺序不订,但依赖的顺序最终
是正确的,同时由于无需建立全局变量,甚至能够作到在同一个页面上同时加载同一模块的不一样版本
一个磁盘文件应该只定义1个模块,多个模块可使用内置优化工具将其组织打包。
一、简单的值对:
若是一个模块仅含值对,没有任何依赖,则在define()中定义这些值对就行了:
define({
color:'black',
size:'unisize'
})
二、函数式定义:
若是一个模块没有任何依赖,但须要一个作setup工做的函数,则在define()中定义该函数
,并将其传给define()
define(function(){
return {
color:'black',
size:'unisize'
}
});
三、存在依赖的函数式定义:
若是模块存在依赖:则第一个参数是依赖的名称数组;第二个参数是函数,在模块的全部依赖加载
完毕后,该函数会被调用来定义该模块,所以该模块应该返回一个定义本模块的object,依赖关系
会以参数的形式注入到该函数上,参数列表与依赖名称列表一一对应。
define(['./cart','./inventory'],function(cart,inventory){
return {
color:'blue',
size:'large',
addTocart:function(){
inventory.decrement(this);
cart.add(this);
}
}
})
本示例建立了一个my/shirt模块,它依赖于my/cart及my/inventory。磁盘上各文件分布以下:
· my/cart.js
· my/inventory.js
· my/shirt.js
模块函数以参数‘cart’及‘inventory’使用这两个以‘./cart’及‘./inventoty’名称指定的模块
在这两个模块加载完毕以前,模块函数不会被调用
严重不鼓励模块定义全局变量,遵循此处的定义模式,可使得同一模块的不一样版本并存于同一
页面上,另外,函参的顺序应与依赖顺序保存一致
返回的object定义了'my/shirt'模块,这种定义模式下,‘my/shirt’不做为一个全局变量而存在
四、将模块定义为一个函数:
对模块的返回值类型并无强制为必定是个object,任何函数的返回值都是容许的,此处是一个返
回了函数的模块定义:
define(['my/cart','my/inventory'],function(cart,inventory){
return function(title){
return title?(window.title=title):inventory.storeName +'' +cart.name;
}
})
五、简单包装CommonJS来定义模块
若是你现有一些以CommonJS模块格式编写的代码,而这些代码难于使用上述依赖名称数组参数的形式
来重构,你能够考虑直接将这些依赖对应到一些本地变量中进行使用,你可使用一个CommonJS的简
单包装来实现:
define(function(require,exports,module){
var a = require('a'),
b = require('b');
return function(){};
})
该包装方法依靠Function.prototype.toString()将函数内容赋予一个有意义的字串值,但在一些设备
如PS3及一些老的Opera手机浏览器中不起做用,考虑在这些设备上使用优化器将依赖导出为数组形式
六、定义一个命名模块:
你能够会看到一些define()中包含了一个模块名称做为首个参数:
define('foo/title',['my/cart','my/inventory'],function(cart,inventory){
})
这些常由优化工具生成,你也能够本身显示指定模块名称,但这使模块更不具有移植性--就是说若你
将文件移动到其余目录下,你就得重命名,通常最好避免对模块硬编码,而是交给优化工具去生成,
优化工具须要生成模块名以将多个模块打成一个包,加快到浏览的载入速度
其余注意事项:
一个文件一个模块:每一个JavaScript文件应该只定义一个模块,这是模块名-至-文件名查找机制的
天然要求。多个模块会被优化工具组织优化,但你在使用优化工具时,应将多个模块放置到一个文件中
define()中的相对模块名:为了能够在define()内部使用诸如require('./relative/name')的调用以
正确解析相对名称,记得将‘require’自己做为一个依赖诸如到模块中:
define(['require'.'./relative/name'],function(require){
var mod = require('./ralative/name');
})
或者更好地,使用下述为转换CommonJS模块所设的更短的语法:
define(function(require){
var mod = require('./relative/name');
})
相对路径在一些场景下格外有用,例如:为了以便于将代码共享给其余人或项目,你在某个目录下建立
了一些模块,你能够访问模块的相邻模块,无需知道该目录的名称,
生成相对于模块的URL地址:你可能须要生成一个相对于模块的URL地址,你能够将'require'做为一个依赖
注入进来,而后调用require.toUrl()以生成该URL:
define(['require'],function(require){
var cssUrl = require.toUrl('./style.css');
})
控制台调试:若是你须要处理一个已经过require(['module/name'],function(){})
调用加载了的模块,可使用模块名做为字符串参数的require()调用来获取它:
require('module/name').callSomeFunction()
注意这种形式仅在“module/name”已经由其异步形式的require(['module/name'])加载
了后才有效,只能在define内部使用形如“./module/name”的相对路径app
循环依赖:
若是你定义了一个循环依赖(a依赖b,b同时依赖a),则在这种情形下当b的模块函数被
调用的时候,它会获得一个undefined的a,b能够在模块已经定义好后用require()方法再获取
(记得将require做为依赖注入进来):
define(['require','a'],function(require,a){
return function(title){
return require('a').doSomething();
}
})
通常说来你无需使用require()去获取一个模块,而是应当使用注入到模块函数中的依赖。
循环依赖比较罕见,这也是一个重构代码从新设计的警示灯,但无论怎样,有时候仍是要
用到循环依赖,这种情形下就使用上述的require()方式来解决。
若是你熟悉CommonJS,你能够考虑使用exports为模块创建一个空object,该object能够当即
被其余模块引用,在循环依赖的两头都如此操做以后,你就能够安全地持有其余模块了,这种
方法仅在每一个模块都是输出object做为模块值的时候有效,换成函数无效
define(function(require,exports,module){
var a = require('a');
exports.foo = function(){
return a.bar();
}
})
或者,若是你使用依赖注入数组的步骤,则可用注入特殊的"exports"来解决
2、requireJS的升级发生的变化:
一、延迟模块的执行:之前模块加载后factory立马执行,性能上确定会有一些损耗,如今能够等到
require的时候才执行
二、config增长了shim、map、module、enforceDefine
shim参数解决了使用非AMD方式定义的模块(如jQuery插件)及其载入顺序,使用shim参数来取代
1.0版本的order插件其实在1.0版本中就曾经有人开发过use和wrap插件来解决此类问题,考虑到很
多开发者有此类需求(好比某些JS模块是较早时候其余人开发的,非AMD方式)这次2.0版本直接将其
内置其中
下面是一个使用jQuery插件形式配置的参数,咱们知道jQuery插件本质上是将命名空间挂在全局的jQuery
或jQuery.fn上,而非使用define定义的 模块,而jQuery插件都依赖于jQuery,即在require插件时得保证
jQuery先下载下来,能够以下配置:
require.config({
shim:{
'jquery-slide':['jquery']
}
});
require(['jquery-slide'],function(){
})
这时会保证下下载jquery.js,而后在下载jquery-slide.js
map参数用来解决同一模块的不一样版本问题,这一灵感来自于Dojo的packageMap。有这样的场景:
开发初期使用了的jquery-1.6.4,后期升级到了1.7.2,但担忧有些依赖jquery-1.6.4的代码升级到
1.7.2后有问题,所以保守的让这部分代码继续使用1.6.4版本,这时map参数将派上用场。假如A,B
模块中使用了jquery-1.6.4.js,C,D模块中使用了jquery-1.7.2.js。以下:
require.config({
map:{
'A':{
'jquery':'jquery-1.6.4'
},
'B':{
'jquery':'jquery-1.7.4'
}
}
})
require(['A'])将会下载jquery-1.6.4,require(['B'])会下载jquery-1.7.2。若是模块A写成*
则表示除了B模块使用jquery-1.7.2以外其余模块都是用jquery-1.6.4,map参数解决了模块的各
个版本问题,很好的向下兼容了老代码
config参数用来给指定的模块传递一些有用的数据,以下;
require.config({
config: {
'A':{
info : {name :'jack'}
}
}
})
使用A的模块中能够经过A.config().info获取到该数据信息。如
require(['A'],function(A){
var info = A.config().info;
console.log(info);
})
enforceDefine用来强制模块使用define定义,默认为false,如underscore再也不支持AMD后
其代码移除了define,此时若是仍然使用requirejs来载入他, 他就是普通的js文件了,此时
若是enforceDefine设为true,虽然underscore.js能下载,但requirejs会报错,
require函数增长了第三个参数errbacks
很明显该函数指模块文件没有载入成功时的回调
require(['b'],function(){
console.log('success')
},function(err){
console.log(err)
})
err会给出一些出错提示信息
更强大的paths参数:
能够配置成一个数组,顺序映射,当前面的路径没有成功载入,能够接着使用后面的路径
require.config({
enforceDefine:true,
paths:{
jquery:[
'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min',
'lib/jquery'
]
}
})
require(['jquery'],function($){
})
在模块载入失败回调中可使用undef函数移除模块的注册:
require(['jquery'],function($){
},function(err){
var failedId = err.requireModules && err.requireModules[0];
if(failId === 'jquery'){
requirejs.undef(failedId)
}
})
2、压缩
压缩:
node r.js -o baseUrl=js name=main out=built.js
-o表示优化,该参数是固定的,必选
baseUrl值存放模块的跟目录,这里是r4/js,由于cd到r4中了,只需设置为js,可选,若是没有设置将从
r4中查找main.js,
main 模块的入口文件,这里设置成main,那么r.js会从baseUrl+main去查找,这里实际是r4/js/main.js
找出其所依赖的全部其余模块,而后合并压缩
out 指合并压缩后输出的文件路径,这里直接是built.js,那么输出到根目录r4下
2个参数:
excludeShallow 合并时将排除该文件
node r.js -o baseUrl=js name=main out=built.js excludeShallow=selector
optimize(none/uglify/closure)指定是否压缩,默认为uglify
不传该参数时r.js默认以uglifyJS压缩,设置为none则不会压缩,仅合并,这在开发阶段是颇有用的
node r.js -o baseUrl=js name=main out=built.js optimize=none 这时生成的built.js是没有压缩的