
1、認識require.js:
官方文檔:http://requirejs.org/
RequireJS是一個非常小巧的JavaScript模塊載入框架,是AMD規范最好的實現者之一。最新版本的RequireJS壓縮后只有14K,堪稱非常輕量。它還同時可以和其他的框架協同工作,使用RequireJS必將使您的前端代碼質量得以提升。
RequireJS 是一個JavaScript模塊加載器。它非常適合在瀏覽器中使用, 但它也可以用在其他腳本環境, 就像 Rhino and Node. 使用RequireJS加載模塊化腳本將提高代碼的加載速度和質量。
2、require.js的優點:
- 2.1、異步加載,防止js阻塞頁面渲染;
- 2.2、按需加載,避免在初始化網頁的時候,產生大量的請求和數據傳輸;防止出現如下丑陋的場景:
<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>
- 2.3、更加方便的模塊依賴管理。相信你曾經一定遇到過因為script標簽順序問題而導致依賴關系發生錯誤,這個函數未定義,那個變量undefine之類的。通過RequireJS的機制,你能確保在所有的依賴模塊都加載以后再執行相關的文件,所以可以起到依賴管理的作用。
- 2.4、更加高效的版本管理。想一想,如果你還是用的script腳本引入的方式來引入一個jQuery2.x的文件,然后你有100個頁面都是這么引用的,那當你想換成jQuery3.x,那你就不得不去改這100個頁面。但是如果你的requireJS有在config中做jQuery的path映射,那你只需要改一處地方即可。
3、在網頁中未使用require.js和使用require.js比較
網頁中未使用require.js編寫方式:
index.html:
<!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已經出現在頁面中。
4、熟悉requirejs基本API
require會定義三個變量:define,require,requirejs,其中require === requirejs,一般使用require更簡短;
一個回調函數:callback
- ● define 從名字就可以看出這個api是用來定義一個模塊
- ● require 加載依賴模塊,並執行加載完后的回調函數
- ● callback,一個function,是用來處理加載完畢后的邏輯
用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()來進行優化。
5、用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后綴的,當然也是不能寫后綴
6、requirejs的使用方法
- 6.1、首先要到requirejs的網站去下載js -> requirejs.org或者到我的網盤下載;
- 6.2、然后在index.html頁面中使用下面的方式來使用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也寫上。
- 6.3、添加全局配置文件main.js
注意:前提是需要在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
})
- 6.4、a.js實現AMD規范的寫法
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){
.....
})
但是,這樣做感覺不很有必要,因為如果哪一天我將這個文件轉移到其他目錄下,那我就得在這這里再修改一次模塊名。官方其實也不推薦,用官方的說法是:讓優化工具去自動生成這些模塊名吧!
- 6.5、加載非規范化模塊
理論上,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值(輸出的變量名),表明這個模塊外部調用時的名稱;
7、require.js提供了一個優化工具r.js
require.js提供了一個優化工具r.js或者到網盤下載,當模塊部署完畢以后,可以用這個工具將多個模塊合並在一個文件中,減少HTTP請求數。
具體使用方法,請參考下節:require.js實現js模塊化編程(二):RequireJS Optimizer
8、相關文檔:
require.js,實現具體的項目構建,請自行下載,謝謝關注。
