1. 程式人生 > >requireJS的基本用法

requireJS的基本用法

   引言

   目前專案中的前端架構採用的是RequireJS+AngularJS,小編在工作之餘對這個前端框架比較感興趣,在開始的

時候對這個框架不是很懂,因為裡面有很多平臺自己封裝的東西,所以在理解起來不是很容易,經過這一段時間在項

目中的運用有了一定的理解,下面先來總結總結一下其中的一個技術點——RequireJS的基本用法。

   基本介紹

    RequireJS是一個JavaScript檔案或者模組的載入器。它可以提高JavaScript檔案的載入速度,避免不必要的

堵塞。它針對於在瀏覽器環境中使用做過專門的優化,但它也可以在其他的JavaScript環境中使用,像Node.js一樣

可以在伺服器上執行。說了這麼多廢話,其實它為我們提供了兩種思路解決大量載入js檔案帶來的問題:

   1、模組化組織JS

   2、非同步載入js檔案

  為什麼需要用RequireJS?

   當我們業務比較負載時候我們有時候需要在一個頁面中引入大量的js檔案,之前的ITOO中會見到一個頁面引入

了很多的js檔案,原先我們的寫法是這樣的:

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

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

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

這樣寫的有很多的缺點:

    1、頁面在載入的時候從上往下開始載入和渲染的,當頁面有很多分散的JS檔案的時候,頁面會先載入和解析

頭部的js檔案(同步載入),此時頁面渲染就被堵塞了,如果這些js檔案請求的數量比較多,那麼網頁失去響應的時

間就會加長。

   2、如果js檔案之間是有相互依賴關係的,那麼我們的js檔案引入的順序需要我們一定要注意,依賴性大的檔案

一定在最後引入,但是當依賴關係非常複雜的時候,程式碼的編寫和維護就非常複雜了。

  然上面引入JS時候,對於第1點:首先:我們可以放在底部去載入,把所有JS放在</body>之前去,這樣就會解決

了遊覽器堵塞的問題,其次我們可以把所有的JS檔案打包成一個JS檔案,但是依賴性(也就是順序)我們還是沒有辦法

解決掉,所以我們引入了requireJS(優點:1、實現JS檔案的非同步載入,避免網頁被堵塞。2、管理模組之間的依賴

性,便於程式碼的編寫和維護。)。

   requireJS的基本語法及用法

   1、在官網上下載requireJS包,在我們頁面的頭部引入require.js檔案,基本用法如下:

<head>
    <meta charset="UTF-8">
    <title>RequirJS測試</title>
    <script src="RequireJS/require.js" defer async="true" data-main="RequireJS/app.js"></script>
</head>

  sync屬性表明檔案需要非同步載入,IE不支援這個屬性,只支援defer,所以上面把這2個屬性都加上。接下來,看

看requireJS啟動載入指令碼的初始化方式,requireJS支援屬性 data-main 這個屬性來載入初始化的JS檔案,其中

app.js檔案也即是我們的入口(主)檔案,如果我們的app.js檔案的內容為空的話,載入順序如下:


  定義模組檔案

   首先看一個Demo的目錄結構(webstorm開發):

             

   RequireJS編寫模組不同於其他指令碼檔案,它良好的使用define來定義一個作用域避免全域性空間汙染,它可以顯

示出其依賴關係,並以函式(定義此模組的那個函式)引數的形式將這些依賴進行注入。大家如果對JS中的閉包比較熟

悉的話,這個東西非常的好理解,因為在我看來它就是解決js閉包解決的問題。

 b.js中我們寫一個簡單例子:

/**
 * Created by zhenghao on 2016/7/4.
 */
define(function(){

    var add = function(x,y) {

        return x + y;

    };
    return {

        add : add
    }
});

   在入口檔案app.js中寫入一下內容:

/**
 * Created by zhenghao on 2016/7/4.
 */
 require(['app/b'], function (m){

 console.log(m.add(1,3));

 });


  我們會在瀏覽器的console介面看到輸入4,說明我們呼叫成功了,我們來看一下載入順序:


   當然我們也可以編寫簡單的鍵值對直接返回一個物件,從而解決全域性變數的問題,如下:

   a.js檔案的內容:

/**
 * Created by zhenghao on 2016/7/4.
 */
define(function () {
    return {
        color: "black",

        size: "unisize"
    }
});

  app.js初始化檔案:
require(['app/a'], function (m){

 console.log(m);

 });

  執行結果:

 

 直接返回一個物件,通過使用上面的方法我們可以想到可以解決全域性變數概念,比如全域性變數全部使用define函式

包圍,什麼時候需要全域性變數的話,直接require([‘XX’],function(XX){})這樣呼叫下,同時所有的JS都是非同步

的,並不會堵塞載入。

   requireJS配置項介紹

    1、baseUrl:指定本地模組的基準目錄,即本地模組的路徑是相對於那個目錄的,該屬性通常有requireJS載入

時的data-main屬性指定。比如如下程式碼

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


  app.js檔案的內容:

requirejs.config({

    baseUrl: 'RequireJS/app'

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

});

     我們在瀏覽器中看到如下請求路徑:


   如上可以看到,View.html和RequireJS是同一個目錄下的,都是放在requireJS資料夾裡面的,所以定義

baseUrl:’RequireJS/app’ 會自動解析成 requireJSService/RequireJS/app/ 所以

requirejs([‘a’,’b’,’c’])的話,會自動到requireJSService/RequireJS/app/目錄下去查詢a.js,b.js,

c.js.找到了就可以加載出來.

   如果未顯示設定baseUrl,則預設值是載入require.js的html所處的位置,如果使用了data-main屬性的話,則該

路徑變成了baseUrl.如下程式碼:

<span style="font-size:18px;"><script src="RequireJS/require.js" defer async="true" data-main="RequireJS/app.js"></script></span>

   app.js檔案的內容:

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

});


   如上顯示:預設情況下是從data-main檔案入口去載入RequireJS/app.js程式碼的,但是現在app.js中並沒有設定

config配置項,所以使用requirejs([‘a’,’b’,’c’],function(a,b,c))的時候會繼續載入RequireJS下面的

a.js,b.js,c.js,如果找到就載入,沒有找到就顯示404 not found,如上所示。

   2、path:paths是對映那些不直接放在baseUrl指定的目錄下的檔案,設定paths的起始位置是相對於baseUrl

的,除非該path設定是以”/”開頭或含有URL協議(http://或者https://).

   app.js檔案的內容如下:

requirejs.config({
    baseUrl: 'RequireJS/lib',
    paths: {
        app: '../app'
    }
});
requirejs(['app/a'],function(a){

});

  可以看到paths是相對於baseUrl配置項生成的,baseUrl:’RequireJS/lib’下的所有js檔案,但是paths下的 

app:’../app’是相對於js/lib下設定的,’..’的解析到js目錄下,然後就解析成RequireJS/app下,再

require([‘app/a’]),就解析到RequireJS/app/a.js了。

   當我們把baseUrl註釋掉的話,a.js可定就找不到了,此時載入的路徑如下:

requirejs.config({
    //baseUrl: 'RequireJS/lib',
    paths: {
        app: '../app'
    }
});
requirejs(['app/a'],function(a){

})

  

   3、skim引數:理論上,require.js載入的模組,必須是按照AMD規範、用define()函式定義的模組。但是實際

上,雖然已經有一部分流行的函式庫(比如jQuery)符合AMD規範,更多的庫並不符合,而skim解決了使用非AMD方式

定義的模組(如jquery外掛)及其載入順序,為那些沒有使用define()來宣告依賴關係,設定模組的”瀏覽器全域性變數

注入”型指令碼做依賴和匯出配置。

   app.js中的程式碼如下:

require.config({
    baseUrl: 'RequireJS/lib',
    paths: {

        'app': '../app',
        'temp':'../app/depBase',
        'jquery':'../lib/jquery-1.7.1',
        'a':'../app/a'
    },
    shim: {

        'temp': { exports:'_',deps: ['jquery'] }
    }
});

require(['temp','a'],function(base){

    console.log(base);

});
  檔案載入順序及載入結果



   require.config()接受一個配置物件,這個物件除了有前面說過的paths屬性之外,還有一個shim屬性,專門用

來配置不相容的模組。具體來說,每個模組要定義(1)exports值(輸出的變數名),表明這個模組外部呼叫時的名

稱;(2)deps陣列,表明該模組的依賴性。

  4、map引數:對於給定的模組字首,使用一個不同的模組ID來載入該模組。這個手段在大型專案中是非常重要

的,比如我們不同的模組需要載入不同版本的jquery檔案,這就需要我們用到這個map來給我們解決了,比如我們

a.js檔案需要依賴jquery-1.7.1,而我們的b.js檔案需要依賴jquery-1.8.0。請看下面例子:

  app.js檔案中的程式碼:

requirejs.config({
    map: {
        'app/a': {
            'jquery': 'RequireJS/lib/jquery-1.7.1.js'
        },
        'app/b': {
            'jquery': 'RequireJS/lib/jquery-1.8.0.min.js'
        }
    }
});

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

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

});

   a.js檔案和b.js檔案中的內容如下:

define(function (require, exports, module) {

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

});
define(function (require, exports, module) {

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

});


   我們只加載b.js檔案的時候的檔案載入結果:



   如果我們只加載a.js檔案,那麼我們會看到載入的是jquery-1.7.1.js檔案。

   5.config引數:這個和我們c#中的配置檔案一樣,我們一般將易變的或者application級別的資訊配置在

config裡面,同樣這個東西在requireJS中也是支援的,但是這就需要我們提供一種手段將裡面的配置的資訊傳遞到

每一個模組中,基於requirejs.config()的config配置項來實現。要獲取這些資訊的模組可以載入特殊的依

賴 ”moudle” ,並呼叫module.config().

   app.js檔案中的程式碼:

requirejs.config({
    config: {
        'app/c': {
            name: '鄭浩'
        },
        'app/d': {
            age: 18
        }
    }
});
require(['app/c'],function(c){
    console.log(c);
});

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

 c.js檔案和d.js檔案中的程式碼如下:
define(function (require, exports, module) {
//其值是'鄭浩'
    var size = module.config().name;
    return size;

});

<span style="font-family:SimSun;font-size:18px;">define(['module'], function (module) {
    var color = module.config().age;
    return color;

});</span>



   最後贈送

 其實require和我們之前過的ajax或者$http有類似地方就是在回撥函式上面,當我們在加載出錯的時候會走第二個

回撥函式,程式碼如下:

require(['b'], function ($) {
     //Do something with $ here
}, function (err) {
    alert(err)
});

  

   小結

   以上就是小編對requireJS的一些理解和總結,其中的例子都是對現在專案中一個縮影,上面講解的一些屬性和

引數都在我們專案中出現過,也是我們在使用requireJS經常用到的一些基本知識,裡面有一些東西還不是很明白,

需要在專案中繼續學習和研究,希望對讀者有些幫助