requireJS使用教程

一:爲何要使用requireJS?html

好久以前,咱們全部的JS文件寫到一個js文件裏面去進行加載,可是當業務愈來愈複雜的時候,須要分紅多個JS文件進行加載,好比在頁面中head內分別引入a.js,b.js,c.js等,以下所示: node

<script src="js/app/a.js"></script>

<script src="js/app/b.js"></script>

 <script src="js/app/c.js"></script>

咱們如今先在瀏覽器下看看這些請求,以下所示:jquery

這樣的寫法有以下缺點:數組

1. 頁面在加載的時候,是從頁面自上往下加載及渲染的,當頁面上有多個分散的js文件時候,頁面會先加載及解析頭部的JS文件(同步加載),頁面被堵塞了,其次分散的js請求數多了,網頁失去響應的時間就會變長。瀏覽器

2. 因爲JS文件存在依賴關係,好比上面的b.js要依賴於a.js,因此務必保證a.js優先引入到頁面上來且先加載,要嚴格保證加載順序,依賴性最大的文件必定要放到最後加載。可是當依賴關係很複雜的時候,代碼的編寫和維護就會變得困難了。app

固然上面引入JS時候,對於第1點:首先:咱們能夠放在底部去加載,把全部JS放在</body>以前去,這樣就會解決了遊覽器堵塞的問題,其次咱們能夠把全部的JS文件打包成一個JS文件,可是依賴性(也就是順序)咱們仍是沒有辦法解決掉,因此咱們引入了requireJS。jquery插件

二:使用requireJS的優勢有哪些?異步

1.  實現JS文件的異步加載,避免網頁被堵塞。async

2.  管理模塊之間的依賴性,便於代碼的編寫和維護。函數

requireJS基本語法及使用.

 1.  首先咱們須要到官網下載最新版本的requireJS源碼包。 下載地址: ,

在頁面頭部head標籤內引入requireJS,以下:<script src="js/require.js"></script>,可是加載這個文件也會形成網頁失去響應,咱們能夠加上 defer 和 async這個屬性。以下:

<script src="js/require.js" defer async="true" ></script>

Async屬性代表文件須要異步加載,IE不支持這個屬性,只支持defer,因此上面把這2個屬性都加上。接下來,看看requireJS啓動加載腳本的初始化方式,requireJS支持屬性 data-main 這個屬性來加載初始化的JS文件,以下:

<script src="js/require.js" defer async="true" data-main="js/app.js"></script>

上面的意思是:先異步加載requireJS文件,完成後繼續異步加載app.js文件,假如app.js內容爲空的話,咱們能夠看看加載順序以下:

上面的app.js後的.js能夠去掉,由於requireJS源碼已經默認都是之後綴JS文件結尾的。

 2.  如何定義模塊文件?

RequireJS編寫模塊不一樣於其餘腳本文件,它良好的使用define來定義一個做用域避免全局空間污染,它能夠顯示出其依賴關係,並以函數(定義此模塊的那個函數)參數的形式將這些依賴進行注入。

下面咱們來看下demo,以下新建一個項目文件:

咱們先在app/b.js下添加基本的requireJS代碼以下:

// b.js
define(function(){
    var add = function(x,y) {
        return x + y;
    };
    return {
        add : add
    }
});    

使用define來定義模塊,下面咱們須要在app.js裏面來加載b.js模塊,以下在app.js裏面來調用了。

require(['app/b'], function (b){

    console.log(b.add(1,1));

});

咱們接着看看文件加載的狀況以下:

在head標籤內動態生成文件,以下:

能夠看到加載順序 requirejs --> app.js --> b.js。

上面的是函數式的定義如上面方式編寫代碼(使用define定義一個函數),咱們還能夠編寫簡單的鍵值對,直接返回一個對象(能夠解決全局變量的理念),咱們如今在a.js裏面返回這麼一個對象,以下:

// a.js
define(function () {
    return {
        color: "black",
        size: "unisize"
    }
});

//在app.js初始化代碼以下:
require(['app/a'],function(a){
    console.log(a);
});

  

咱們在控制檯上能夠看到以下:

直接返回一個對象,經過使用上面的方法咱們能夠想到能夠解決全局變量概念,好比全局變量所有使用define函數包圍,何時須要全局變量的話,直接require([‘XX’],function(XX){})這樣調用下,同時全部的JS都是異步的,並不會堵塞加載。

3. AMD模塊規範

第一種寫法:
define(function() { 
    return { 
        mix: function(source, target) { 
        } 
    }; 
});

第二種寫法 有依賴項 以下:
define(['data', 'ui'], function(data, ui) { 
    // init here 
});

第三種寫法 直接一個對象
define({ 
    data: [], 
    ui: [] 
});

第四種寫法 具名模塊 以下:
define('index', ['data','base'], function(data, base) { 
    // todo 
});

第五種寫法 包裝模塊 以下:
define(function(require, exports, module) { 
    var base = require('base'); 
    exports.show = function() { 
        // todo with module base 
    }  
});

書寫格式和nodeJS比較像,可使用require獲取模塊,使用exports或者module.exports導出API。

固然requireJS是遵循AMD的規範的,因此通常狀況下也具備上面的書寫代碼方式。

對於第四種寫法 具名模塊寫法咱們並不推薦的,由於不書寫模塊名咱們同樣能夠調用,且在合併代碼的時候,咱們也能夠根據代碼自動生成模塊名,若是咱們如今寫死了模塊名,當某個時候,b.js我要移動到其餘目錄時候,JS也要跟着改,因此代碼維護方面很差,因此不建議書寫模塊名。對於第五種寫法,requireJS中也是支持的,經過內部調用require來處理依賴模塊,咱們也能夠試着作demo看看就知道了,仍是app.js,我想初始化a.js代碼,我改爲這樣的方式,以下代碼:

define(function(require, exports, module) { 
    var a = require('app/a');
    console.log(a);
    exports.show = function() { 
          / / todo with module base 
    }  
});

經過控制檯也能夠看到已經打印出 a 出來。

注意: 一、 書寫requireJS遵循一個文件一個模塊。

二、 不要手動寫模塊名標示。

4. requireJS配置項以下:

1.baseUrl: 指定本地模塊的基準目錄,即本地模塊的路徑是相對於那個目錄的,該屬性一般有requireJS加載時的data-main屬性指定。好比以下代碼:

項目目錄結構仍是上面的。

在頁面頂部<head>中引入 <script src="js/require.js" defer async="true" data-main="js/app"></script>

在app.js以下代碼:

requirejs.config({
    baseUrl: 'js/app'
});

requirejs(['a','b','c'],function(a,b,c){

});

  

在瀏覽器頁面遊覽能夠看到以下請求:

如上能夠看到,index.html和js是同一個目錄下的,都是放在requireJS文件夾裏面的,因此定義baseUrl:’js/app’ 會自動解析成 requireJS/js/app/ 因此requirejs([‘a’,’b’,’c’])的話,會自動到requireJS/js/app/目錄下去查找a.js,b.js,c.js.找到了就能夠加載出來。

若是未顯示設置baseUrl,則默認值是加載require.js的html所處的位置,若是使用了data-main屬性的話,則該路徑變成了baseUrl.以下代碼:

Index.html代碼以下:

<script src="js/require.js" defer async="true" data-main="js/app"></script>

App.js代碼以下:

requirejs(['a','b','c'],function(a,b,c){

});

那麼在瀏覽器下會被解析成以下:

如上顯示:默認狀況下是從data-main文件入口去加載js/app.js代碼的,可是如今app.js中並無設置config配置項,因此使用requirejs([‘a’,’b’,’c’],function(a,b,c))的時候會繼續加載js下面的a.js,b.js,c.js,若是找到就加載,沒有找到就顯示404 not found,如上所示。

    2.paths: paths是映射那些不直接放在baseUrl指定的目錄下的文件,設置paths的起始位置是相對於baseUrl的,除非該path設置是以」/」開頭或含有URL協議(http://或者https://).

以下在app.js代碼:

requirejs.config({
    baseUrl: 'js/lib',
    paths: 
        app: '../app'
    }
});

requirejs(['app/a'],function(a){

});    

  

在頁面上加載顯示以下:

能夠看到paths是相對於baseUrl配置項生成的,baseUrl:’js/lib’下的全部js文件,可是paths下的 app:’../app’是相對於js/lib下設置的,’..’的解析到js目錄下,而後就解析成js/app下,再require([‘app/a’]),就解析到js/app/a.js了。

若是app.js代碼註釋掉baseUrl時,變成以下代碼:

requirejs.config({
    //baseUrl: 'js/lib',
    paths: {
        app: '../app'
    }
});

requirejs(['app/a'],function(a){  });

那麼就被加載成這個樣子了,以下所示:

直接把app/a.js放在項目文件requirejs下了。

3. shim參數  解決了使用非AMD方式定義的模塊(如jquery插件)及其載入順序,爲那些沒有使用define()來聲明依賴關係,設置模塊的」瀏覽器全局變量注入」型腳本作依賴和導出配置。

在js/app目錄下新建文件 depBase.js 代碼以下:

define(function(){
    return {
        "a":11
    }
})

接着在app.js文件裏面把代碼改爲以下:
require.config({
    baseUrl: 'js/lib',
    shim: {
        'app/depBase': ['jquery']
    },
    paths: {
        app: '../app'
    }
});

require(['app/depBase'],function(base){
    console.log(base);
});

而後在瀏覽器查看請求以下:

由上面能夠看到,我require(['app/depBase'],function(base){console.log(base);});這個,它先加載baseUrl中的配置 js/lib下的jquery文件,而後再加載js/app/depBase.js文件。也就是說shim這個參數能夠解決沒有使用define(function(){})這樣的文件包圍的代碼或者一些全局變量注入,能夠確保此文件先加載,而後再加載其餘文件。

可是若是我不使用shim這個參數的話,在最新版的requirejs2.1.15中(之前的版本我不太清楚),也能夠經過require([‘XX’])來解決,以下演示:

好比我在js/app文件下新建global.js文件,如今的目錄以下:

其中global.js代碼以下:

names = 1111;

創造一個全局變量names,其中js/app/depBase.js代碼變成以下:

define(function(){
    return {
        'name':names
    }
})

也就是說我在app.js代碼以下初始化以下:

require.config({
    baseUrl: 'js/app'
});

require(['global','depBase'],function(global,base){
    console.log(base);
});

我先global初始化引入全局變量names,接着打印出depBase的返回值,截圖以下:

也能夠看到,能夠引入到全局變量names的值。

4.Map參數: Map參數是用來解決同一個模塊不一樣版本的問題,好比在項目開發中,開發初期使用了jquery1.7版本,可是因爲業務的需求須要引入jquery1.9以上的版本時候,可是又擔憂有些是依賴於jquery1.7的代碼升級到1.9以上的時候會有問題,所以可讓一部分代碼仍是依賴於jquery1.7,薪增的代碼依賴於jquery1.9.

下面咱們來看看咱們目錄結構以下所示:

我在lib文件下新增jquery1.7.js和 jquery1.9.1.js,如今我在入口文件app.js添加以下代碼:

requirejs.config({

map: {

'app/a': {

'jquery': 'js/lib/jquery1.7.js'

},

'app/b': {

'jquery': 'js/lib/jquery1.9.1.js'

}

}

});

require(['app/a'],function(jq){   

});

require(['app/b'],function(jq){  

});

而後在app/a.js添加以下代碼:

// a.js

define(function (require, exports, module) {

var a = require(['jquery']);

});

在app/b.js添加以下代碼:

// b.js

define(function (require, exports, module) {

var b = require(['jquery']);

});

在app.js中

require(['app/a'],function(jq){  

});時候,在加載app/a.js的時候會加載jquery1.7.js文件,在加載app/b.js的時候會加載jquery1.9.1.js.以下截圖所示:

若是在app.js中把下面這行b.js代碼初始化註釋掉

require(['app/b'],function(jq){   

});

那麼就只會加載app/a.js及對應的jquery1.7.js,截圖以下:

相應的 若是把app/a.js初始化代碼註釋掉,把app/b.js代碼初始化打開,那麼只會加載jquery1.9.1,能夠看到若是我想app/b.js中使用jquery1.9的話,那麼能夠這樣使用了。

 5.config參數。  config是指須要將配置信息傳給一個模塊,這些配置每每是application級別的信息,須要一個手段將他們向下傳遞給模塊。在requireJS中,基於requirejs.config()的config配置項來實現。要獲取這些信息的模塊能夠加載特殊的依賴 」moudle」 ,並調用module.config().

首先咱們能夠仍是試着作demo來理解下上面話的意思吧,我如今在項目requirejs下js/app文件下新建一個d.js. 而後在app.js初始化文件加入以下代碼:

requirejs.config({
    config: {
        'app/c': {
            size: 'large'
        },
        'app/d': {
            color: 'blue'
        }
    }
});

require(['app/c'],function(c){
    console.log(c);
});

require(['app/d'],function(dss){
    console.log(d);
});

在c.js裏面這樣寫代碼:
define(function (require, exports, module) {
    //其值是'large'
    var size = module.config().size;
    return size;
});

在控制檯下運行能夠看到能打印出 large值出來,這說明咱們能夠經過config配置項來給app/c.js傳遞一個模塊信息,好比如上面的一個對象{size:large},而在c.js裏面直接能夠經過module.config()方法來獲取size的值。

下面咱們可使用一個依賴數組來作一樣的事情,以下d.js代碼:

define(['module'], function (module) {
    //Will be the value 'blue'
    var color = module.config().color;
    return color;
});

在控制檯看 也同樣能夠打印出color值出來。

6. 內部機制:

RequireJS加載的每一個模塊做爲script Tag,使用head.appendChild()方法。

在模塊的定義時,requireJS等到全部的依賴都加載完畢,會爲函數的調用計算出正確的順序,而後在函數中經過正確的順序進行調用。

7. requireJS函數增長了第三個參數errbacks

仍是作demo來演示下,咱們仍是在入口文件app.js下增長代碼,以下:

原本加載b模塊是app/b  可是我故意寫錯成b 因此就不會執行第一個回調函數,轉而到第二個回調函數內。以下彈框:

8.在模塊載入失敗回調中可使用undef函數移除模塊的註冊。

以下代碼:

代碼:
require(['b'], function ($) {
    //Do something with $ here
}, function (err) {
    var failedId = err.requireModules && err.requireModules[0];
    if (failedId === 'b') {
        requirejs.undef(failedId);
    }
});    
相關文章
相關標籤/搜索