RequireJS的目標是鼓勵代碼的模塊化,它使用了不一樣於傳統<script>標籤的腳本加載步驟。能夠用它來加速、優化代碼,但其主要目的仍是爲了代碼的模塊化。javascript
RequireJS以一個相對於baseUrl的地址來加載全部的代碼。 頁面頂層<script>標籤含有一個特殊的屬性data-main,require.js使用它來啓動腳本加載過程,而baseUrl通常設置到與該屬性相一致的目錄。css
baseUrl亦可經過RequireJS config手動設置。若是沒有顯式指定config及data-main,則默認的baseUrl爲包含RequireJS的那個HTML頁面的所屬目錄。html
RequireJS默認假定全部的依賴資源都是js腳本,所以無需在module ID上再加".js"後綴,RequireJS在進行module ID到path的解析時會自動補上後綴。你能夠經過paths config設置一組腳本,這些有助於咱們在使用腳本時碼更少的字。java
有時候你想避開"baseUrl + paths"的解析過程,而是直接指定加載某一個目錄下的腳本。此時能夠這樣作:若是一個module ID符合下述規則之一,其ID解析會避開常規的"baseUrl + paths"配置,而是直接將其加載爲一個相對於當前HTML文檔的腳本:node
通常來講,最好仍是使用baseUrl及"paths" config去設置module ID。它會給你帶來額外的靈活性,如便於腳本的重命名、重定位等。 同時,爲了不凌亂的配置,最好不要使用多級嵌套的目錄層次來組織代碼,而是要麼將全部的腳本都放置到baseUrl中,要麼分置爲項目庫/第三方庫的一 個扁平結構,以下:jquery
index.html:git
<script data-main="js/app.js" src="js/require.js"></script>
app.js:github
requirejs.config({ //By default load any module IDs from js/lib baseUrl: 'js/lib', //except, if the module ID starts with "app", //load it from the js/app directory. paths //config is relative to the baseUrl, and //never includes a ".js" extension since //the paths config could be for a directory. paths: { app: '../app' } }); //Start the main app logic. requirejs(['jquery', 'canvas', 'app/sub'], function ($, canvas, sub) { //jQuery, canvas and the app/sub module are all //loaded and can be used here now. });
注意在示例中,三方庫如jQuery沒有將版本號包含在他們的文件名中。咱們建議將版本信息放置在單獨的文件中來進行跟蹤。使用諸如volo這類的工具,能夠將package.json打上版本信息,並在磁盤上保持文件名爲"jquery.js"。這有助於你保持配置的最小化,避免爲每一個庫版本設置一條path。例如,將"jquery"配置爲"jquery-1.7.2"。web
理想情況下,每一個加載的腳本都是經過define()來定義的一個模塊;但有些"瀏覽器全局變量注入"型的傳統/遺留庫並無使用define() 來定義它們的依賴關係,你必須爲此使用shim config來指明它們的依賴關係。 若是你沒有指明依賴關係,加載可能報錯。這是由於基於速度的緣由,RequireJS會異步地以無序的形式加載這些庫。ajax
require.js 在加載的時候會檢察data-main 屬性:
<script data-main="scripts/main" src="scripts/require.js"></script>
你能夠在data-main指向的腳本中設置模板加載 選項,而後加載第一個應用模塊。.注意:你在main.js中所設置的腳本是異步加載的。因此若是你在頁面中配置了其它JS加載,則不能保證它們所依賴的JS已經加載成功。例如:
<script data-main="scripts/main" src="scripts/require.js"></script> <script src="scripts/other.js"></script>
// contents of main.js: require.config({ paths: { foo: 'libs/foo-1.1.3' } });
// contents of other.js: // This code might be called before the require.config() in main.js has executed. // When that happens, require.js will attempt to load 'scripts/foo.js' instead of 'scripts/libs/foo-1.1.3.js' require( ['foo'], function( foo ) { });
模塊不一樣於傳統的腳本文件,它良好地定義了一個做用域來避免全局名稱空間污染。它能夠顯式地 列出其依賴關係,並以函數(定義此模塊的那個函數)參數的形式將這些依賴進行注入,而無需引用全局變量。RequireJS的模塊是模塊模式的一個擴展, 其好處是無需全局地引用其餘模塊。
RequireJS的模塊語法容許它儘快地加載多個模塊,雖然加載的順序不定,但依賴的順序最終是正確的。同時由於無需建立全局變量,甚至能夠作到在同一個頁面上同時加載同一模塊的不一樣版本。
一個磁盤文件應該只定義 1 個模塊。多個模塊可使用內置優化工具將其組織打包。
若是一個模塊僅含值對,沒有任何依賴,則在define()中定義這些值對就行了:
//Inside file my/shirt.js: define({ color: "black", size: "unisize" });
若是一個模塊沒有任何依賴,但須要一個作setup工做的函數,則在define()中定義該函數,並將其傳給define():
//my/shirt.js now does setup work //before returning its module definition. define(function () { //Do setup work here return { color: "black", size: "unisize" } });
若是模塊存在依賴:則第一個參數是依賴的名稱數組;第二個參數是函數,在模塊的全部依賴加載完畢後,該函數會被調用來定義該模塊,所以該模塊應該返回一個定義了本模塊的object。依賴關係會以參數的形式注入到該函數上,參數列表與依賴名稱列表一一對應。
//my/shirt.js now has some dependencies, a cart and inventory module in the same directory as shirt.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); } } } );
本示例建立了一個my/shirt模塊,它依賴於my/cart及my/inventory。磁盤上各文件分佈以下:
模塊函數以參數"cart"及"inventory"使用這兩個以"./cart"及"./inventory"名稱指定的模塊。在這兩個模塊加載完畢以前,模塊函數不會被調用。
嚴重不鼓勵模塊定義全局變量。遵循此處的定義模式,可使得同一模塊的不一樣版本並存於同一個頁面上(參見 高級用法 )。另外,函參的順序應與依賴順序保存一致。
返回的object定義了"my/shirt"模塊。這種定義模式下,"my/shirt"不做爲一個全局變量而存在。
對模塊的返回值類型並無強制爲必定是個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; } });
若是你現有一些以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手機瀏覽器中不起做用。考慮在這些設備上使用優化器將依賴導出爲數組形式。
你可能會看到一些define()中包含了一個模塊名稱做爲首個參數:
//Explicitly defines the "foo/title" module: define("foo/title",["my/cart", "my/inventory"],function(cart, inventory) { //Define foo/title object in here. }
);
這些常由優化工具生成。你也能夠本身顯式指定模塊名稱,但這使模塊更不具有移植性——就是說若你將文件移動到其餘目錄下,你就得重命名。通常最好避免對模塊硬編碼,而是交給優化工具去生成。優化工具須要生成模塊名以將多個模塊打成一個包,加快到瀏覽器的載人速度。
一個文件一個模塊: 每一個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"的相對路徑。
若是你定義了一個循環依賴(a依賴b,b同時依賴a),則在這種情形下當b的模塊函數被調用的時候,它會獲得一個undefined的a。b能夠在模塊已經定義好後用require()方法再獲取(記得將require做爲依賴注入進來):
//Inside b.js: define(["require", "a"], function(require, a) { //"a" in this case will be null if a also asked for b, //a circular dependency. return function(title) { return require("a").doSomething(); } } );
通常說來你無需使用require()去獲取一個模塊,而是應當使用注入到模塊函數參數中的依賴。循環依賴比較罕見,它也是一個重構代碼從新設計的警示燈。但無論怎樣,有時候仍是要用到循環依賴,這種情形下就使用上述的require()方式來解決。
若是你熟悉CommonJS,你能夠考慮使用exports爲模塊創建一個空object,該object能夠當即被其餘模塊引用。在循環依賴的兩頭都如此操做以後,你就能夠安全地持有其餘模塊了。這種方法僅在每一個模塊都是輸出object做爲模塊值的時候有效,換成函數無效。
//Inside b.js: define(function(require, exports, module) { //If "a" has used exports, then we have a real object reference here. //However, we cannot useany of a's properties until after b returns a value. var a = require("a"); exports.foo = function () { return a.bar(); }; });
或者,若是你使用依賴注入數組的步驟,則可用注入特殊的"exports"來解決:
//Inside b.js: define(['a', 'exports'], function(a, exports) { //If "a" has used exports, then we have a real object reference here. //However, we cannot useany of a's properties until after b returns a value. exports.foo = function () { return a.bar(); }; });
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 theJSONP data call. console.log(data); } );
僅支持返回值類型爲JSON object的JSONP服務,其餘返回類型如數組、字串、數字等都不能支持。
RequireJS使用head.appendChild()將每個依賴加載爲一個script標籤。
RequireJS等待全部的依賴加載完畢,計算出模塊定義函數正確調用順序,而後依次調用它們。
在同步加載的服務端JavaScript環境中,可簡單地重定義require.load()來使用RequireJS。build系統就是這麼作的。該環境中的require.load實現可在build/jslib/requirePatch.js中找到。
將來可能將該部分代碼置入require/目錄下做爲一個可選模塊,這樣你能夠在你的宿主環境中使用它來得到正確的加載順序。
當在頂層HTML頁面(或不做爲一個模塊定義的頂層腳本文件)中,可將配置做爲首項放入:
<script src="scripts/require.js"></script> <script> require.config({ baseUrl: "/another/path", paths: { "some": "some/v1.0" }, waitSeconds: 15 }); require( ["some/module", "my/module", "a.js", "b.js"], function(someModule, myModule) { //This function will be called when all the dependencies //listed above are loaded. Note that this function could //be called before the page is loaded. //This callback is optional. } ); </script>
<script> var require = { deps: ["some/module1", "my/module2", "a.js", "b.js"], callback: function(module1, module2) { //This function will be called when all the dependencies //listed above in deps are loaded. Note that this //function could be called before the page is loaded. //This callback is optional. } }; </script> <script src="scripts/require.js"></script>
或者,你將配置做爲全局變量"require"在require.js加載以前進行定義,它會被自動應用。下面的示例定義的依賴會在require.js一旦定義了require()以後即被加載:
requirejs.config({ bundles: { 'primary': ['main', 'util', 'text', 'text!template.html'], 'secondary': ['text!secondary.html'] } }); require(['util', 'text'], function(util, text) { //The script for module ID 'primary' was loaded, //and that script included the define()'d //modules for 'util' and 'text' });
注意: 最好使用 var require = {} 的形式而不是 window.require = {}的形式。後者在IE中運行不正常。
支持的配置項:
baseUrl :全部模塊的查找根路徑。因此上面的示例中,"my/module"的標籤src值是"/another/path/my/module.js"。當加載純.js文件(依賴字串以/開頭,或者以.js結尾,或者含有協議),不會使用baseUrl。所以a.js及b.js都在包含上述代碼段的HTML頁面的同目錄下加載。
如未顯式設置baseUrl,則默認值是加載require.js的HTML所處的位置。若是用了data-main屬性,則該路徑就變成baseUrl。
paths :path映射那些不直接放置於baseUrl下的模塊名。設置path時起始位置是相對於baseUrl的,除非該path設置以"/"開頭或含有URL協議(如http:)。在上述的配置下,"some/module"的script標籤src值是"/another/path/some/v1.0/module.js"。
用於模塊名的path不該含有.js後綴,由於一個path有可能映射到一個目錄。路徑解析機制會自動在映射模塊名到path時添加上.js後綴。在文本模版之類的場景中使用require.toUrl()時它也會添加合適的後綴。
在瀏覽器中運行時,可指定路徑的備選(fallbacks),以實現諸如首先指定了從CDN中加載,一旦CDN加載失敗則從本地位置中加載這類的機制。
shim: 爲那些沒有使用define()來聲明依賴關係、設置模塊的"瀏覽器全局變量注入"型腳本作依賴和導出配置。
下面有個示例,它須要 RequireJS 2.1.0+,而且假定backbone.js、underscore.js 、jquery.js都裝於baseUrl目錄下。若是沒有,則你可能須要爲它們設置paths config:
requirejs.config({ //Remember: only use shim config for non-AMD scripts,scripts that do not already call define(). //The shimconfig will not work correctly if used on AMD scripts, //in particular, the exports and init config will notbe triggered, and the deps config will be confusingfor those cases. shim: { 'backbone': { //These script dependencies should be loaded before loadingbackbone.js|譯|在加載backbone.js以前應先加載它的依賴函數underscore.js和jquery.js deps: ['underscore', 'jquery'], //Once loaded, use the global 'Backbone' as themodule value.|譯|加載完畢後該模塊使用的引用名 exports: 'Backbone' }, 'underscore': { exports: '_' }, 'foo': { deps: ['bar'], exports: 'Foo', init: function (bar) { //Using a function allows you to call noConflict forlibraries that support it, and do other cleanup. //However, plugins for those libraries may still want a global. //"this" for the function will be the global object. //The dependencies will be passed in as function arguments. //If this function returns a value,then that value is used as the module export valueinstead of the object found via the 'exports' string. //Note: jQuery registers as an AMD module via define(),so this will not work for jQuery. //See notes sectionbelow for an approach for jQuery. return this.Foo.noConflict(); } } } }); //Then, later in a separate file, call it 'MyModel.js', a module is defined,specifting 'backbone' as a dependency. //RequireJS will use the shim config to properly load 'backbone' and give a local reference to this module. //The global Backbone will still exist on the page too. define(['backbone'], function (Backbone) { return Backbone.Model.extend({}); });
RequireJS 2.0.*中,shim配置中的"exports"屬性能夠是一個函數而不是字串。這種狀況下它就起到上述示例中的"init"屬性的功能。 RequireJS 2.1.0+中加入了"init"承接庫加載後的初始工做,以使exports做爲字串值被enforceDefine所使用。
那些僅做爲jQuery或Backbone的插件存在而不導出任何模塊變量的"模塊"們,shim配置可簡單設置爲依賴數組:
requirejs.config({ shim: { 'jquery.colorize': ['jquery'], 'jquery.scroll': ['jquery'], 'backbone.layoutmanager': ['backbone'] } });
但請注意,若你想在IE中使用404加載檢測以啓用path備選(fallbacks)或備錯(errbacks),則須要給定一個字串值的exports以使loader可以檢查出腳本是否實際加載了(init中的返回值不會用於enforceDefine檢查中):
requirejs.config({ shim: { 'jquery.colorize': { deps: ['jquery'], exports: 'jQuery.fn.colorize' }, 'jquery.scroll': { deps: ['jquery'], exports: 'jQuery.fn.scroll' }, 'backbone.layoutmanager': { deps: ['backbone'] exports: 'Backbone.LayoutManager' } } });
"shim"配置的重要注意事項:
shim配置僅設置了代碼的依賴關係,想要實際加載shim指定的或涉及的模塊,仍然須要一個常規的require/define調用。設置shim自己不會觸發代碼的加載。
請僅使用其餘"shim"模塊做爲shim腳本的依賴,或那些沒有依賴關係,而且在調用define()以前定義了全局變量(如jQuery或lodash)的AMD庫。不然,若是你使用了一個AMD模塊做爲一個shim配置模塊的依賴,在build以後,AMD模塊可能在shim託管代碼執行以前都不會被執行,這會致使錯誤。終極的解決方案是將全部shim託管代碼都升級爲含有可選的AMD define()調用。(這一塊不明白~~!!!)
"shim"配置的優化器重要注意事項:
您應當使用 mainConfigFile build配置項來指定含有shim配置的文件位置,不然優化器不會知曉shim配置。另外一個手段是將shim配置複製到build profile中。(這一塊不明白~~!!!)
不要在一個build中混用CDN加載和shim配置。示例場景,如:你從CDN加載jQuery的同時使用shim配置加載依賴於jQuery的原版Backbone。不要這麼作。您應該在build中將jQuery內聯而不是從CDN加載,不然build中內聯的Backbone會在CDN加載jQuery以前運行。這是由於shim配置僅延時加載到全部的依賴已加載,而不會作任何define的自動裝裹(auto-wrapping)。在build以後,全部依賴都已內聯,shim配置不能延時執行非define()的代碼。define()的模塊能夠在build以後與CDN加載代碼一併工做,由於它們已將本身的代碼合理地用define裝裹了,在全部的依賴都已加載以前不會執行。所以記住:shim配置僅是個處理非模塊(non-modular)代碼、遺留代碼的將就手段,如能夠應儘可能使用define()的模塊。
對於本地的多文件build,上述的CDN加載建議仍然適用。任何shim過的腳本,它們的依賴必須加載於該腳本執行以前。這意味着要麼直接在含有shim腳本的build層build它的依賴,要麼先使用require([], function (){})調用來加載它的依賴,而後對含有shim腳本的build層發出一個嵌套的require([])調用。
若是您使用了uglifyjs來壓縮代碼,不要將uglify的toplevel選項置爲true,或在命令行中不要使用 -mt。 該選項會破壞shim用於找到exports的全局名稱。
map: 對於給定的模塊前綴,使用一個不一樣的模塊ID來加載該模塊。
該手段對於某些大型項目很重要:若有兩類模塊須要使用不一樣版本的"foo",但它們之間仍須要必定的協同。 在那些基於上下文的多版本實現中很難作到這一點。並且,paths配置僅用於爲模塊ID設置root paths,而不是爲了將一個模塊ID映射到另外一個。map示例:
requirejs.config({ map: { 'some/newmodule': { 'foo': 'foo1.2' }, 'some/oldmodule': { 'foo': 'foo1.0' } } });
若是各模塊在磁盤上分佈以下:
當「some/newmodule」調用了「require('foo')」,它將獲取到foo1.2.js文件;而當「some/oldmodule」調用「`require('foo')」時它將獲取到foo1.0.js。
該特性僅適用於那些調用了define()並將其註冊爲匿名模塊的真正AMD模塊腳本。而且,請在map配置中僅使用絕對模塊ID,「../some/thing」之類的相對ID不能工做。
另外在map中支持「*」,意思是「對於全部的模塊加載,使用本map配置」。若是還有更細化的map配置,會優先於「*」配置。示例:
requirejs.config({ map: { '*': { 'foo': 'foo1.2' }, 'some/oldmodule': { 'foo': 'foo1.0' } } });
意思是除了「some/oldmodule」外的全部模塊,當要用「foo」時,使用「foo1.2」來替代。對於「some/oldmodule」本身,則使用「foo1.0」。
config:經常須要將配置信息傳給一個模塊。這些配置每每是application級別的信息,須要一個手段將它們向下傳遞給模塊。在RequireJS中,基於requirejs.config()的config配置項來實現。要獲取這些信息的模塊能夠加載特殊的依賴「module」,並調用module.config()。示例:
requirejs.config({ config: { 'bar': { size: 'large' }, 'baz': { color: 'blue' } } }); //bar.js, which uses simplified CJS wrapping: //http://requirejs.org/docs/whyamd.html#sugar define(function (require, exports, module) { //Will be the value 'large' var size = module.config().size; }); //baz.js which uses a dependency array, //it asks for the special module ID, 'module': //https://github.com/jrburke/requirejs/wiki/Differences-between-the-simplified-CommonJS-wrapper-and-standard-AMD-define#wiki-magic define(['module'], function (module) { //Will be the value 'blue' var color = module.config().color; });
若要將config傳給包,將目標設置爲包的主模塊而不是包ID:
requirejs.config({ //Pass an API key for use in the pixie package'smain module. config: { 'pixie/index': { apiKey: 'XJKDLNS' } }, //Set up config for the "pixie" package, whose mainmodule is the index.js file in the pixie folder. packages: [ { name: 'pixie', main: 'index' } ] });
packages: 從CommonJS包(package)中加載模塊。
nodeIdCompat: 在放棄加載一個腳本以前等待的秒數。設爲0禁用等待超時。默認爲7秒。
waitSeconds: 命名一個加載上下文。這容許require.js在同一頁面上加載模塊的多個版本,若是每一個頂層require調用都指定了一個惟一的上下文字符串。
deps: 指定要加載的一個依賴數組。當將require設置爲一個config object在加載require.js以前使用時頗有用。一旦require.js被定義,這些依賴就已加載。使用deps就像調用require([]),但它在loader處理配置完畢以後就當即生效。它並不阻塞其餘的require()調用,它僅是指定某些模塊做爲config塊的一部分而異步加載的手段而已。
callback: 在deps加載完畢後執行的函數。當將require設置爲一個config object在加載require.js以前使用時頗有用,其做爲配置的deps數組加載完畢後爲require指定的函數。
enforceDefine: 若是設置爲true,則當一個腳本不是經過define()定義且不具有可供檢查的shim導出字串值時,就會拋出錯誤。
xhtml: 若是設置爲true,則使用document.createElementNS()去建立script元素。
urlArgs: RequireJS獲取資源時附加在URL後面的額外的query參數。做爲瀏覽器或服務器未正確配置時的「cache bust」手段頗有用。使用cache bust配置的一個示例:
urlArgs: "bust=" + (new Date()).getTime()
在開發中這頗有用,但請記得在部署到生成環境以前移除它。
scriptType: 指定RequireJS將script標籤插入document時所用的type=""值。默認爲「text/javascript」。想要啓用Firefox的JavaScript 1.8特性,可以使用值「text/javascript;version=1.8」。
RequireJS支持從CommonJS包結構中加載模塊,但須要一些額外的配置。具體地,支持以下的CommonJS包特性:
重要事項
若是你使用了相似於入門指導中的項目佈局,你的web項目應大體以以下的佈局開始(基於Node/Rhino的項目也是相似的,只不過使用scripts目錄中的內容做爲項目的頂層目錄):
而下面的示例中使用了兩個包,cart及store:
project.html 會有以下的一個script標籤:
<script data-main="scripts/main" src="scripts/require.js"></script>
對「cart」的依賴請求會從scripts/cart/main.js中加載,由於「main」是RequireJS默認的包主模塊。對「store/util」的依賴請求會從scripts/store/util.js加載。
若是「store」包不採用「main.js」約定,以下面的結構:
則RequireJS的配置應以下:
require.config({ packages: [ "cart", { name: "store", main: "store" } ] });
減小麻煩期間,強烈建議包結構聽從「main.js」約定。
如配置項一節中所述,能夠在同一頁面上以不一樣的「上下文」配置項加載同一模塊的不一樣版本。require.config()返回了一個使用該上下文配置的require函數。下面是一個加載不一樣版本(alpha及beta)模塊的示例(取自test文件中):
<script src="../require.js"></script> <script> var reqOne = require.config({ context: "version1", baseUrl: "version1" }); reqOne(["require", "alpha", "beta",], function(require, alpha, beta) { log("alpha version is: " + alpha.version); //prints 1 log("beta version is: " + beta.version); //prints 1 setTimeout(function() { require(["omega"], function(omega) { log("version1 omega loaded with version: " + omega.version); //prints 1 } ); }, 100); }); var reqTwo = require.config({ context: "version2", baseUrl: "version2" }); reqTwo(["require", "alpha", "beta"], function(require, alpha, beta) { log("alpha version is: " + alpha.version); //prints 2 log("beta version is: " + beta.version); //prints 2 setTimeout(function() { require(["omega"], function(omega) { log("version2 omega loaded with version: " + omega.version); //prints 2 } ); }, 100); }); </script>
注意「require」被指定爲模塊的一個依賴,這就容許傳遞給函數回調的require()使用正確的上下文來加載多版本的模塊。若是「require」沒有指定爲一個依賴,則極可能會出現錯誤。
上述多版本示例中也展現瞭如何在嵌套的require()中遲後加載代碼。
從版本0.12開始,RequireJS可在Web Worker中運行。能夠經過在web worker中調用importScripts()來加載require.js(或包含require()定義的JS文件),而後調用require就行了。
你可能須要設置baseUrl配置項來確保require()可找到待加載腳本。
你能夠在unit test使用的一個文件中找到一個例子。
RequireJS可經過r.js適配器用在Rhino中。
一般的錯誤都是404(未找到)錯誤,網絡超時或加載的腳本含有錯誤。RequireJS有些工具來處理它們:require特定的錯誤回調(errback),一個「paths」數組配置,以及一個全局的requirejs.onError事件。
傳入errback及requirejs.onError中的error object一般包含兩個定製的屬性:
若是你獲得了requireModules錯,可能意味着依賴於requireModules數組中的模塊的其餘模塊未定義。
Internet Explorer有一系列問題致使檢測errbacks/paths fallbacks中的加載錯 比較困難:
所以IE環境下很難一箭雙鵰:匿名AMD(AMD模塊機制的核心優點)和可靠的錯誤檢測。
但若是你的項目裏使用了define()來定義全部模塊,或者爲其餘非define()的腳本使用shim配置指定了導出字串,則若是你將enforceDefine配置項設爲true,loader就能夠經過檢查define()調用或shim全局導出值來確認腳本的加載無誤。
所以若是你打算支持Internet Explorer,捕獲加載錯,並使用了define()或shim,則記得將enforceDefine設置爲true。參見下節的示例。
注意: 若是你設置了enforceDefine: true,並且你使用data-main=""來加載你的主JS模塊,則該主JS模塊必須調用define()而不是require()來加載其所需的代碼。主JS模塊仍然可調用require/requirejs來設置config值,但對於模塊加載必須使用define()。
當與requirejs.undef()一同使用errback時,容許你檢測模塊的一個加載錯,而後undefine該模塊,並重置配置到另外一個地址來進行重試。
一個常見的應用場景是先用庫的一個CDN版本,若是其加載出錯,則切換到本地版本:
requirejs.config({ enforceDefine: true, paths: { jquery: 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min' } }); //Later require(['jquery'], function ($) { //Do something with $ here }, function (err) { //The errback, error callback //The error has a list of modules that failed var failedId = err.requireModules && err.requireModules[0]; if (failedId === 'jquery') { //undef is function only on the global requirejs object. //Use it to clear internal knowledge of jQuery. //Any modules that were dependent on jQuery and in the middle of loading will not be loaded yet, //they will wait until a valid jQuerydoes load. requirejs.undef(failedId); //Set the path to jQuery to local path requirejs.config({ paths: { jquery: 'local/jquery' } }); //Try again. Note that the above require callback //with the "Do something with $ here" comment will //be called if this new attempt to load jQuery succeeds. require(['jquery'], function () {}); } else { //Some other error. Maybe show message to the user. } });
使用「requirejs.undef()」,若是你配置到不一樣的位置並從新嘗試加載同一模塊,則loader會將依賴於該模塊的那些模塊記錄下來並在該模塊從新加載成功後去加載它們。
注意: errback僅適用於回調風格的require調用,而不是define()調用。define()僅用於聲明模塊。
上述模式(檢錯,undef()模塊,修改paths,重加載)是一個常見的需求,所以有一個快捷設置方式。paths配置項容許數組值:
requirejs.config({ //To get timely, correct error triggers in IE, force a define/shim exports check. enforceDefine: true, paths: { jquery: [ 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min', //If the CDN location fails, load from this location 'lib/jquery' ] } }); //Later require(['jquery'], function ($) { });
上述代碼先嚐試加載CDN版本,若是出錯,則退回到本地的lib/jquery.js。
注意: paths備錯僅在模塊ID精確匹配時工做。這不一樣於常規的paths配置,常規配置可匹配模塊ID的任意前綴部分。備錯主要用於很是的錯誤恢復,而不是常規的path查找解析,由於那在瀏覽器中是低效的。
爲了捕獲在局域的errback中未捕獲的異常,你能夠重載requirejs.onError():
requirejs.onError = function (err) { console.log(err.requireType); if (err.requireType === 'timeout') { console.log('modules: ' + err.requireModules); } throw err; };
RequireJS支持加載器插件。使用它們可以加載一些對於腳本正常工做很重要的非JS文件。RequireJS的wiki有一個插件的列表。本節討論一些由RequireJS一併維護的特定插件:
若是都能用HTML標籤而不是基於腳本操做DOM來構建HTML,是很不錯的。但沒有好的辦法在JavaScript文件中嵌入HTML。所能作的僅是在js中使用HTML字串,但這通常很難維護,特別是多行HTML的狀況下。.
RequireJS有個text.js插件能夠幫助解決這個問題。若是一個依賴使用了text!前綴,它就會被自動加載。參見text.js的README文件。
RequireJS加載模塊速度很快,頗有可能在頁面DOM Ready以前腳本已經加載完畢。須要與DOM交互的工做應等待DOM Ready。現代的瀏覽器經過DOMContentLoaded事件來知會。
可是,不是全部的瀏覽器都支持DOMContentLoaded。domReady模塊實現了一個跨瀏覽器的方法來斷定什麼時候DOM已經ready。下載並在你的項目中如此用它:
require(['domReady'], function (domReady) { domReady(function () { //This function is called once the DOM is ready. //It will be safe to query the DOM and manipulateDOM nodes in this function. }); });
基於DOM Ready是個常規需求,像上述API中的嵌套調用方式,理想狀況下應避免。domReady模塊也實現了Loader Plugin API,所以你可使用loader plugin語法(注意domReady依賴的!前綴)來強制require()回調函數在執行以前等待DOM Ready。當用做loader plugin時,domReady會返回當前的document:
require(['domReady!'], function (doc) { //This function is called once the DOM is ready, //notice the value for 'domReady!' is the currentdocument. });
注意: 若是document須要一段時間來加載(也許是由於頁面較大,或加載了較大的js腳本阻塞了DOM計算),使用domReady做爲loader plugin可能會致使RequireJS「超時」錯。若是這是個問題,則考慮增長waitSeconds配置項的值,或在require()使用domReady()調用(將其當作是一個模塊)。