requireJS的使用_API(1)

以前有介紹過requireJS(模塊化開發),能夠看看 ,可是不詳細,因此今天參考官網來詳細介紹一下:javascript

1.加載js文件:

RequireJS的目標是鼓勵代碼的模塊化,它使用了不一樣於傳統<script>標籤的腳本加載步驟。能夠用它來加速、優化代碼,但其主要目的仍是爲了代碼的模塊化。它鼓勵在使用腳本時以module ID替代URL地址。css

RequireJS以一個相對於baseUrl的地址來加載全部的代碼。 頁面頂層<script>標籤含有一個特殊的屬性data-main,require.js使用它來啓動腳本加載過程,而baseUrl通常設置到與該屬性相一致的目錄。下列示例中展現了baseUrl的設置:html

<script data-main="js/main.js" src="js/require.js"></script>

baseUrl亦可經過RequireJS config手動設置。若是沒有顯式指定config及data-main,則默認的baseUrl爲包含RequireJS的那個HTML頁面的所屬目錄。java

RequireJS默認假定全部的依賴資源都是js腳本,所以無需在module ID上再加".js"後綴,RequireJS在進行module ID到path的解析時會自動補上後綴。能夠經過paths config設置一組腳本,這些有助於咱們在使用腳本時碼更少的字。jquery

<script data-main="js/main" src="js/require.js"></script>

有時候你想避開"baseUrl + paths"的解析過程,而是直接指定加載某一個目錄下的腳本。此時能夠這樣作:若是一個module ID符合下述規則之一,其ID解析會避開常規的"baseUrl + paths"配置,而是直接將其加載爲一個相對於當前HTML文檔的腳本:json

  • 以 ".js" 結束.
  • 以 "/" 開始.
  • 包含 URL 協議, 如 "http:" or "https:".

通常來講,最好仍是使用baseUrl及"paths" config去設置module ID。它會給你帶來額外的靈活性,如便於腳本的重命名、重定位等。 同時,爲了不凌亂的配置,最好不要使用多級嵌套的目錄層次來組織代碼,而是要麼將全部的腳本都放置到baseUrl中,要麼分置爲項目庫/第三方庫的一個扁平結構,以下:canvas

  • www/
    • index.html
    • js/
      • app/
        • sub.js
      • lib/
        • jquery.js
        • canvas.js
      • app.js

index.html:api

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

app.js:跨域

requirejs.config({
    //默認的相對加載路徑
    baseUrl: 'js/lib',
    paths: {
        app: '../app'
    }
});
requirejs(['jquery', 'canvas', 'app/sub'],
    function   ($, canvas, sub) {
        //加載成功後執行的函數
    });

2.data-main 入口點:

require.js 在加載的時候會檢察data-main 屬性:數組

你能夠在data-main指向的腳本中設置模板加載 選項,而後加載第一個應用模塊。.注意:你在main.js中所設置的腳本是異步加載的。因此若是你在頁面中配置了其它JS加載,則不能保證它們所依賴的JS已經加載成功

3.定義模塊:

模塊不一樣於傳統的腳本文件,它良好地定義了一個做用域來避免全局名稱空間污染。它能夠顯式地列出其依賴關係,並以函數(定義此模塊的那個函數)參數的形式將這些依賴進行注入,而無需引用全局變量。RequireJS的模塊是模塊模式的一個擴展,其好處是無需全局地引用其餘模塊。

RequireJS的模塊語法容許它儘快地加載多個模塊,雖然加載的順序不定,但依賴的順序最終是正確的。同時由於無需建立全局變量,甚至能夠作到在同一個頁面上同時加載同一模塊的不一樣版本。

(若是你熟悉ConmmonJS,可參看CommonJS的註釋信息以瞭解RequireJS模塊到CommonJS模塊的映射關係)。(----很差意思。我還沒研究ConmmonJS,期待下一次的學習嘍!!)

一個磁盤文件應該只定義 1 個模塊。多個模塊可使用內置優化工具將其組織打包。

(1)簡單的值對:

若是一個模塊僅含值對,沒有任何依賴,則在define()中定義這些值對就行了:

define({
    color: "black",
    size: "unisize"
});

(2)函數式定義:

若是一個模塊沒有任何依賴,但須要一個作setup工做的函數,則在define()中定義該函數,並將其傳給define():

//before returning its module definition.
define(function () {
    //Do setup work here

    return {
        color: "black",
        size: "unisize"
    }
});

(3)存在依賴的函數式定義:

若是模塊存在依賴:則第一個參數是依賴的名稱數組;第二個參數是函數,在模塊的全部依賴加載完畢後,該函數會被調用來定義該模塊,所以該模塊應該返回一個定義了本模塊的object。依賴關係會以參數的形式注入到該函數上,參數列表與依賴名稱列表一一對應。

看例子:(在shirt.js中定義一個模塊,其中cart.js和inventory.js是和它在同一個目錄下的)

define(["./cart", "./inventory"], function(cart, inventory) {
        //return an object to define the "my/shirt" module.
        return {
            color: "blue",
            size: "large",
            addToCart: function() {
                inventory.decrement(this);
                cart.add(this);
            }
        }
    }
);

模塊函數以參數"cart"及"inventory"使用這兩個以"./cart"及"./inventory"名稱指定的模塊。在這兩個模塊加載完畢以前,模塊函數不會被調用。

嚴重不鼓勵模塊定義全局變量。遵循此處的定義模式,可使得同一模塊的不一樣版本並存於同一個頁面上(參見 高級用法 )(But,我沒看呢,還。「高級用法」,一會看一下吧。)。另外,函參的順序應與依賴順序保存一致。

返回的object定義了"my/shirt"模塊。這種定義模式下,"my/shirt"不做爲一個全局變量而存在。

(4)將模塊定義爲一個函數:  

對模塊的返回值類型並無強制爲必定是個object,任何函數的返回值都是容許的。此處是一個返回了函數的模塊定義:

//A module definition inside foo/title.js. It uses
//my/cart and my/inventory modules from before,
//but since foo/title.js is in a different directory than
//the "my" modules, it uses the "my" in the module dependency
//name to find them. The "my" part of the name can be mapped
//to any directory, but by default, it is assumed to be a
//sibling to the "foo" directory.

define(["my/cart", "my/inventory"], function(cart, inventory) { //return a function to define "foo/title". //It gets or sets the window title. return function(title) { return title ? (window.title = title) : inventory.storeName + ' ' + cart.name; } } );

(5)簡單包裝CommonJS來定義模塊:

若是你現有一些以CommonJS模塊格式編寫的代碼,而這些代碼難於使用上述依賴名稱數組參數的形式來重構,你能夠考慮直接將這些依賴對應到一些本地變量中進行使用。你可使用一個CommonJS的簡單包裝來實現:

define(function(require, exports, module) {
        var a = require('a'),
            b = require('b');

        //Return the module value
        return function () {};
    }
);

該包裝方法依靠Function.prototype.toString()將函數內容賦予一個有意義的字串值,但在一些設備如PS3及一些老的Opera手機瀏覽器中不起做用。考慮在這些設備上使用優化器將依賴導出爲數組形式。

更多的信息可參看CommonJS Notes頁面,以及"Why AMD"頁面的"Sugar"段落.

(6)定義一個命名模塊:

你可能會看到一些define()中包含了一個模塊名稱做爲首個參數:

 //Explicitly defines the "foo/title" module:
    define("foo/title",
        ["my/cart", "my/inventory"],
        function(cart, inventory) {
            //Define foo/title object in here.
       }
    );

這些常由優化工具生成。你也能夠本身顯式指定模塊名稱,但這使模塊更不具有移植性——就是說若你將文件移動到其餘目錄下,你就得重命名。通常最好避免對模塊硬編碼,而是交給優化工具去生成。優化工具須要生成模塊名以將多個模塊打成一個包,加快到瀏覽器的載人速度。

(7)注意事項:

  ①一個文件一個模塊: 

  每一個Javascript文件應該只定義一個模塊,這是模塊名-至-文件名查找機制的天然要求。多個模塊會被優化工具組織優化,但你在使用優化工具時應將多個模塊放置到一個文件中。

  ②define()中的相對模塊名:

   爲了能夠在define()內部使用諸如require("./relative/name")的調用以正確解析相對名稱,記得將"require"自己做爲一個依賴注入到模塊中:

define(["require", "./relative/name"], function(require) {
    var mod = require("./relative/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"的相對路徑。

(8)循環依賴:

JSONP是在javascript中服務調用的一種方式。它僅需簡單地經過一個script標籤發起HTTP GET請求,是實現跨域服務調用一種公認手段。

爲了在RequireJS中使用JSON服務,需要將callback參數的值指定爲"define"。這意味着你可將獲取到的JSONP URL的值當作是一個模塊定義。

下面是一個調用JSONP API端點的示例。該示例中,JSONP的callback參數爲"callback",所以"callback=define"告訴API將JSON響應包裹到一個"define()"中:

require(["http://example.com/api/data.json?callback=define"],
    function (data) {
        //The data object will be the API response for the
        //JSONP data call.
        console.log(data);
    }
);

JSONP的這種用法應僅限於應用的初始化中。一旦JSONP服務超時,其餘經過define()定義了的模塊也可能得不得執行,錯誤處理不是十分健壯。

僅支持返回值類型爲JSON object的JSONP服務,其餘返回類型如數組、字串、數字等都不能支持。

這種功能不應用於long-polling類的JSONP鏈接——那些用來處理實時流的API。這些API在接收響應後通常會作script的清理,而RequireJS則只能獲取該JSONP URL一次——後繼使用require()或define()發起的的對同一URL的依賴(請求)只會獲得一個緩存過的值。

JSONP調用錯誤通常以服務超時的形式出現,由於簡單加載一個script標籤通常不會獲得很 詳細的網絡錯誤信息。你能夠override requirejs.onError()來過去錯誤。更多的信息請參看錯誤處理部分。

(9)Undefining a Module:

有一個全局函數requirejs.undef()用來undefine一個模塊。它會重置loader的內部狀態以使其忘記以前定義的一個模塊。

可是如有其餘模塊已將此模塊做爲依賴使用了,該模塊就不會被清除,因此該功能僅在無其餘模塊持有該模塊時的錯誤處理中,或者當將來須要加載該模塊時有點用。參見備錯(errbacks)段的示例。

若是你打算在undefine時作一些複雜的依賴圖分析,則半私有的onResourceLoad API可能對你有用。

相關文章
相關標籤/搜索