一、為什麼使用RequireJS? <script src="a.js"></script> <script src="b.js"></script> <script src="c.js"></script> <script src="b.js"></script> <script src="c.j ...
一、為什麼使用RequireJS?
<script src="a.js"></script>
<script src="b.js"></script>
<script src="c.js"></script>
上述多個js文件載入的時候,瀏覽器會停止網頁渲染(JS阻塞瀏覽器渲染),載入文件越多,網頁失去響應的時間就會越長;另外各文件的依賴關係很難管理。
RequireJs的作用:
(1)實現js文件的非同步載入,避免網頁失去響應;
(2)管理模塊之間的依賴性,便於代碼的編寫和維護。
(3)定義了一個作用域來避免全局名稱空間污染。
二、require.js的載入
1.從官網下載最新版本的require,放在js目錄下,使用script引入頁面:
<script src="js/require.js"></script>
為了不阻塞頁面渲染,可以把它放在HTML的最底部或改為如下方式:
<script src="js/require.js" defer async="true" ></script>
async屬性表明該文件需非同步載入(defer屬性相容IE)。
2.載入頁面邏輯代碼:
假定代碼文件是main.js,也放在js目錄下,則用如下幾種方式引入:
方式1:
<script data-main="js/main" src="js/require.js"></script>
data-main屬性指定網頁程式的主入口,這個文件會第一個被requirejs載入。requirejs預設所依賴的資源都是js,所以可以把main.js簡寫成main。
方式2:
在載入require.js後,通過requirejs載入config配置文件(如有),最後載入主模塊:
require([‘configUrl’],function () { //config.js必須通過requirejs載入才能註冊 require([moduleAName],function(moduelA){ //邏輯代碼 }) });
三、主模塊的寫法
// main.js require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){ // some code here });
require()函數接受兩個參數,第一個參數是一個數組,表示當前模塊所依賴的模塊;第二個參數是一個回調函數,當前面指定的模塊都載入成功後,它將被調用。載入的模塊會以參數形式傳入該回調函數,從而在回調函數內部就可以使用這些模塊(被依賴的模塊有return的值)。
require()非同步載入moduleA,moduleB和moduleC,瀏覽器不會失去響應;它指定的回調函數,只有當前面依賴的模塊全部下載並執行對應的回調之後,才會運行。
四、模塊的配置
require.config()方法可以定義模塊的路徑,並以短模塊名的形式進行依賴的定義。該方法可以寫在每個主模塊(main.js)的前面,配合主模塊一起使用。
參數是一個對象,這個對象的paths屬性指定各個模塊的載入路徑。paths可以配置多個路徑,如果遠程cdn庫沒有載入成功,則載入本地的庫。
如果不定義模塊的配置,則在主模塊中的依賴需要寫完整路徑。
在每個頁面按需配置路徑:
require.config({ //註冊模塊的配置,供後面的代碼使用 baseUrl: '/js/', paths: { "jquery":”cdnUrl”, "Jquery/jquery-1.12.0.min" "fixheight": "login/fixheight" } }); require(['jquery', 'fixheight'], function ($, fixHeight) { ...other code; fixHeight.init(); });
或者將config配置作為一個單獨的js文件,然後
require([“configJsUrl”],function(){ //需要在main文件中通過require先非同步載入模塊配置 require([‘ModuleName’],function(Name){ …other code }) })
為了避免每個頁面都要嵌套require,還可以用如下方式:
先創建單獨的config.js文件:
require.config({ //註冊模塊的配置,供後面的代碼使用 baseUrl: "/js/app/", //其他依賴都是對於此位置的相對路徑 // 路徑配置 paths: { underscore: 'vender/underscore.min', backbone:’vender/backbone.min’ jquery: ‘cdnUrl’,'vender/jquery/jquery-1.12.0.min', “模塊短名”:”相對於baseUrl的路徑地址,省略模塊文件的尾碼.js” }, // 非AMD模式編寫的類庫需要重新配置 shim: { underscore: { exports:'_' }, backbone(短模塊名仍需要定義路徑): { exports: 'Backbone', //類庫輸出的變數名,表明這個模塊被外部調用時的名稱 deps:['jquery','underscore'] //該模塊的依賴 } }, urlArgs: "bust=" + document.getElementById('publishDate').attributes['value'].value //js資源的參數,控製版本刷新緩存 }); define([ 'marionette'], function () { }); //仍是會被執行的js代碼,會依次載入需要的模塊
然後通過如下方式使用:
<script data-main="js/config" src="js/require.js"></script>
通過主入口直接將模塊配置註冊到requirejs命名空間中,頁面中後續的require方法無需再註冊,可以直接使用短模塊名進行依賴載入。
如果沒有顯式指定config及data-main,則預設的baseUrl為載入RequireJS的HTML頁面所在目錄。如果指定了data-main而沒有在config中指定根路徑,則該路徑被設為baseUrl。
若想避開"baseUrl + paths"的解析過程,而是直接指定載入某一個目錄下的腳本。可以這樣做:如果一個module ID符合下述規則之一,其ID解析會避開常規的"baseUrl + paths"配置,而是直接將其載入為一個相對於當前HTML文檔路徑的腳本:
• 以 ".js" 結束.
• 以 "/" 開始.
• 包含 URL 協議, 如 "http:" or "https:".
eg. require(['/www/js/app/vender/underscore.min.js'], function (_) {…})
require.js要求,每個模塊是一個單獨的js文件。載入多個模塊就會發出多次HTTP請求,影響網頁的載入速度。因此require.js提供了一個優化工具(r.js),當模塊部署完畢以後,可以用這個工具將多個模塊合併在一個文件中,減少HTTP請求數,但又需要和緩存之間進行取捨。
六、AMD模塊的寫法
require.js載入的模塊,必須按照AMD的規定來寫。即模塊必須採用特定的define()函數來定義,通常返回一個對象,該對象具有供別的模塊使用的方法或屬性;或只執行相關邏輯而無輸出。
七、require.js的相關插件
text插件,允許require.js非同步載入txt、css或html等文本資源供js使用,而不需要在script內構建Html字元串。
define(['text!components/multiple/template.html', 'image!cat.jpg'], function(template,cat){ $('body').append($(template)); document.body.appendChild(cat); } );
註意:
模塊的依賴既可以通過[]引入,也可以在回調函數里通過require()方法引入,效果一樣。因為define方法會通過正則先掃描回調函數中require方法的依賴並下載,然後才執行該回調函數。但此時需要傳入依賴require本身,否則會報錯:
define(function(require){ var helper=require(‘helpModuleUrI’);//也會提前載入該依賴 … })
多個模塊先後多次依賴同一個模塊時,該模塊只會被下載並初始化一次,之後require會保持對其的引用供別的模塊再次使用。
區分require方法的執行和回調的執行:
require('config',callBack1);
require('b',callBack2);
// 兩個require方法會立即執行,但callBack的執行順序不確定,取決於下載的順序。
//不同於以下代碼,會嚴格按順序執行
require('config',function(){
require('b',callBack2)
})