国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

一篇文章掌握RequireJS常用知識

2019-11-20 10:41:49
字體:
供稿:網(wǎng)友

本文采取循序漸進(jìn)的方式,從理論到實(shí)踐,從RequireJS官方API文檔中,總結(jié)出在使用RequireJS過程中最常用的一些用法,并對文檔中不夠清晰具體的內(nèi)容,加以例證和分析,分享給大家供大家參考,具體內(nèi)容如下

1. 模塊化
相信每個前端開發(fā)人員在剛開始接觸js編程時,都寫過類似下面這樣風(fēng)格的代碼:

<script type="text/javascript">  var a = 1;  var b = 2;  var c = a * a + b * b;  if(c> 1) {    alert('c > 1');  }  function add(a, b) {    return a + b;  }  c = add(a,b);</script>
<a href="javascript:;" onclick="click(this);" title="">請點(diǎn)擊</a>

這些代碼的特點(diǎn)是:

  • 到處可見的全局變量
  • 大量的函數(shù)
  • 內(nèi)嵌在html元素上的各種js調(diào)用

當(dāng)然這些代碼本身在實(shí)現(xiàn)功能上并沒有錯誤,但是從代碼的可重用性,健壯性以及可維護(hù)性來說,這種編程方式是有問題的,尤其是在頁面邏輯較為復(fù)雜的應(yīng)用中,這些問題會暴露地特別明顯:

  • 全局變量極易造成命名沖突
  • 函數(shù)式編程非常不利于代碼的組織和管理
  • 內(nèi)嵌的js調(diào)用很不利于代碼的維護(hù),因?yàn)閔tml代碼有的時候是十分臃腫和龐大的

所以當(dāng)這些問題出現(xiàn)的時候,js大牛們就開始尋找去解決這些問題的究極辦法,于是模塊化開發(fā)就出現(xiàn)了。正如模塊化這個概念的表面意思一樣,它要求在編寫代碼的時候,按層次,按功能,將獨(dú)立的邏輯,封裝成可重用的模塊,對外提供直接明了的調(diào)用接口,內(nèi)部實(shí)現(xiàn)細(xì)節(jié)完全私有,并且模塊之間的內(nèi)部實(shí)現(xiàn)在執(zhí)行期間互不干擾,最終的結(jié)果就是可以解決前面舉例提到的問題。一個簡單遵循模塊化開發(fā)要求編寫的例子:

//module.jsvar student = function (name) {    return name && {        getName: function () {          return name;        }      };  },  course = function (name) {    return name && {        getName: function () {          return name;        }      }  },  controller = function () {    var data = {};    return {      add: function (stu, cour) {        var stuName = stu && stu.getName(),          courName = cour && cour.getName(),          current,          _filter = function (e) {            return e === courName;          };        if (!stuName || !courName) return;        current = data[stuName] = data[stuName] || [];        if (current.filter(_filter).length === 0) {          current.push(courName);        }      },      list: function (stu) {        var stuName = stu && stu.getName(),          current = data[stuName];        current && console.log(current.join(';'));      }    }  };//main.jsvar stu = new student('lyzg'),  c = new controller();c.add(stu,new course('javascript'));c.add(stu,new course('html'));c.add(stu,new course('css'));c.list(stu);

以上代碼定義了三個模塊分別表示學(xué)生,課程和控制器,然后在main.js中調(diào)用了controller提供的add和list接口,為lyzg這個學(xué)生添加了三門課程,然后在控制臺顯示了出來。運(yùn)行結(jié)果如下:

javascript;html;css

通過上例,可以看出模塊化的代碼結(jié)構(gòu)和邏輯十分清晰,代碼看起來十分優(yōu)雅,另外由于邏輯都通過模塊拆分,所以達(dá)到了解耦的目的,代碼的功能也會比較健壯。不過上例使用的這種模塊化開發(fā)方式也并不是沒有問題,這個問題就是它還是把模塊引用如student這些直接添加到了全局空間下,雖然通過模塊減少了很多全局空間的變量和函數(shù),但是模塊引用本身還是要依賴全局空間,才能被調(diào)用,當(dāng)模塊較多,或者有引入第三方模塊庫時,仍然可能造成命名沖突的問題,所以這種全局空間下的模塊化開發(fā)的方式并不是最完美的方式。目前常見的模塊化開發(fā)方式,全局空間方式是最基本的一種,另外常見的還有遵循AMD規(guī)范的開發(fā)方式,遵循CMD規(guī)范的開發(fā)方式,和ECMAScript 6的開發(fā)方式。需要說明的是,CMD和ES6跟本文的核心沒有關(guān)系,所以不會在此介紹,后面的內(nèi)容主要介紹AMD以及實(shí)現(xiàn)了AMD規(guī)范的RequireJS。

2. AMD規(guī)范
正如上文提到,實(shí)現(xiàn)模塊化開發(fā)的方式,另外常見的一種就是遵循AMD規(guī)范的實(shí)現(xiàn)方式,不過AMD規(guī)范并不是具體的實(shí)現(xiàn)方式,而僅僅是模塊化開發(fā)的一種解決方案,你可以把它理解成模塊化開發(fā)的一些接口聲明,如果你要實(shí)現(xiàn)一個遵循該規(guī)范的模塊化開發(fā)工具,就必須實(shí)現(xiàn)它預(yù)先定義的API。比如它要求在加載模塊時,必須使用如下的API調(diào)用方式:

require([module], callback)其中:[module]:是一個數(shù)組,里面的成員就是要加載的模塊;callback:是模塊加載完成之后的回調(diào)函數(shù)

所有遵循AMD規(guī)范的模塊化工具,都必須按照它的要求去實(shí)現(xiàn),比如RequireJS這個庫,就是完全遵循AMD規(guī)范實(shí)現(xiàn)的,所以在利用RequireJS加載或者調(diào)用模塊時,如果你事先知道AMD規(guī)范的話,你就知道該怎么用RequireJS了。規(guī)范的好處在于,不同的實(shí)現(xiàn)卻有相同的調(diào)用方式,很容易切換不同的工具使用,至于具體用哪一個實(shí)現(xiàn),這就跟各個工具的各自的優(yōu)點(diǎn)跟項(xiàng)目的特點(diǎn)有關(guān)系,這些都是在項(xiàng)目開始選型的時候需要確定的。目前RequireJS不是唯一實(shí)現(xiàn)了AMD規(guī)范的庫,像Dojo這種更全面的js庫也都有AMD的實(shí)現(xiàn)。

最后對AMD全稱做一個解釋,譯為:異步模塊定義。異步強(qiáng)調(diào)的是,在加載模塊以及模塊所依賴的其它模塊時,都采用異步加載的方式,避免模塊加載阻塞了網(wǎng)頁的渲染進(jìn)度。相比傳統(tǒng)的異步加載,AMD工具的異步加載更加簡便,而且還能實(shí)現(xiàn)按需加載,具體解釋在下一部分說明。

3. JavaScript的異步加載和按需加載
html中的script標(biāo)簽在加載和執(zhí)行過程中會阻塞網(wǎng)頁的渲染,所以一般要求盡量將script標(biāo)簽放置在body元素的底部,以便加快頁面顯示的速度,還有一種方式就是通過異步加載的方式來加載js,這樣可以避免js文件對html渲染的阻塞。

第1種異步加載的方式是直接利用腳本生成script標(biāo)簽的方式:

(function() {  var s = document.createElement('script');  s.type = 'text/javascript';  s.async = true;  s.src = 'http://yourdomain.com/script.js';  var x = document.getElementsByTagName('script')[0];  x.parentNode.insertBefore(s, x);})();

這段代碼,放置在script標(biāo)記內(nèi)部,然后該script標(biāo)記添加到body元素的底部即可。

第2種方式是借助script的屬性:defer和async,defer這個屬性在IE瀏覽器和早起的火狐瀏覽器中支持,async在支持html5的瀏覽器上都支持,只要有這兩個屬性,script就會以異步的方式來加載,所以script在html中的位置就不重要了:

<script defer async="true" type="text/javascript" src="app/foo.js"></script><script defer async="true" type="text/javascript" src="app/bar.js"></script><script defer async="true" type="text/javascript" src="app/main.js"></script>

這種方式下,所有異步j(luò)s在執(zhí)行的時候還是按順序執(zhí)行的,不然就會存在依賴問題,比如如果上例中的main.js依賴foo.js和bar.js,但是main.js先執(zhí)行的話就會出錯了。雖然從來理論上這種方式也算不錯了,但是不夠好,因?yàn)樗闷饋砗芊爆崳疫€有個問題就是頁面需要添加多個script標(biāo)記以及沒有辦法完全做到按需加載。

JS的按需加載分兩個層次,第一個層次是只加載這個頁面可能被用到的JS,第二個層次是在只在用到某個JS的時候才去加載。傳統(tǒng)地方式很容易做到第一個層次,但是不容易做到第二個層次,雖然我們可以通過合并和壓縮工具,將某個頁面所有的JS都添加到一個文件中去,最大程度減少資源請求量,但是這個JS請求到客戶端以后,其中有很多內(nèi)容可能都用不上,要是有個工具能夠做到在需要的時候才去加載相關(guān)js就完美解決問題了,比如RequireJS。

4. RequireJS常用用法總結(jié)
前文多次提及RequireJS,本部分將對它的常用用法詳細(xì)說明,它的官方地址是:http://www.requirejs.cn/,你可以到該地址去下載最新版RequireJS文件。RequireJS作為目前使用最廣泛的AMD工具,它的主要優(yōu)點(diǎn)是:

  • 完全支持模塊化開發(fā)
  • 能將非AMD規(guī)范的模塊引入到RequireJS中使用
  • 異步加載JS
  • 完全按需加載依賴模塊,模塊文件只需要壓縮混淆,不需要合并
  • 錯誤調(diào)試
  • 插件支持

4.01 如何使用RequireJS
使用方式很簡單,只要一個script標(biāo)記就可以在網(wǎng)頁中加載RequireJS:

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

由于這里用到了defer和async這兩個異步加載的屬性,所以require.js是異步加載的,你把這個script標(biāo)記放置在任何地方都沒有問題。

4.02 如何利用RequireJS加載并執(zhí)行當(dāng)前網(wǎng)頁的邏輯JS

4.01解決的僅僅是RequireJS的使用問題,但它僅僅是一個JS庫,是一個被當(dāng)前頁面的邏輯所利用的工具,真正實(shí)現(xiàn)網(wǎng)頁功能邏輯的是我們要利用RequireJS編寫的主JS,這個主JS(假設(shè)這些代碼都放置在main.js文件中)又該如何利用RJ來加載執(zhí)行呢?方式如下:

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

對比4.01,你會發(fā)現(xiàn)script標(biāo)記多了一個data-main,RJ用這個配置當(dāng)前頁面的主JS,你要把邏輯都寫在這個main.js里面。當(dāng)RJ自身加載執(zhí)行后,就會再次異步加載main.js。這個main.js是當(dāng)前網(wǎng)頁所有邏輯的入口,理想情況下,整個網(wǎng)頁只需要這一個script標(biāo)記,利用RJ加載依賴的其它文件,如jquery等。

 4.03 main.js怎么寫
假設(shè)項(xiàng)目的目錄結(jié)構(gòu)為:

main.js是跟當(dāng)前頁面相關(guān)的主JS,app文件夾存放本項(xiàng)目自定義的模塊,lib存放第三方庫。

html中按4.02的方式配置RJ。main.js的代碼如下:

require(['lib/foo', 'app/bar', 'app/app'], function(foo, bar, app) {  //use foo bar app do sth});

在這段JS中,我們利用RJ提供的require方法,加載了三個模塊,然后在這個三個模塊都加載成功之后執(zhí)行頁面邏輯。require方法有2個參數(shù),第一個參數(shù)是數(shù)組類型的,實(shí)際使用時,數(shù)組的每個元素都是一個模塊的module ID,第二個參數(shù)是一個回調(diào)函數(shù),這個函數(shù)在第一個參數(shù)定義的所有模塊都加載成功后回調(diào),形參的個數(shù)和順序分別與第一個參數(shù)定義的模塊對應(yīng),比如第一個模塊時lib/foo,那么這個回調(diào)函數(shù)的第一個參數(shù)就是foo這個模塊的引用,在回調(diào)函數(shù)中我們使用這些形參來調(diào)用各個模塊的方法,由于回調(diào)是在各模塊加載之后才調(diào)用的,所以這些模塊引用肯定都是有效的。

從以上這個簡短的代碼,你應(yīng)該已經(jīng)知道該如何使用RJ了。

4.04 RJ的baseUrl和module ID
在介紹RJ如何去解析依賴的那些模塊JS的路徑時,必須先弄清楚baseUrl和module ID這兩個概念。

html中的base元素可以定義當(dāng)前頁面內(nèi)部任何http請求的url前綴部分,RJ的baseUrl跟這個base元素起的作用是類似的,由于RJ總是動態(tài)地請求依賴的JS文件,所以必然涉及到一個JS文件的路徑解析問題,RJ默認(rèn)采用一種baseUrl + moduleID的解析方式,這個解析方式后續(xù)會舉例說明。這個baseUrl非常重要,RJ對它的處理遵循如下規(guī)則:

  • 在沒有使用data-main和config的情況下,baseUrl默認(rèn)為當(dāng)前頁面的目錄
  • 在有data-main的情況下,main.js前面的部分就是baseUrl,比如上面的scripts/
  • 在有config的情況下,baseUrl以config配置的為準(zhǔn)

上述三種方式,優(yōu)先級由低到高排列。

data-main的使用方式,你已經(jīng)知道了,config該如何配置,如下所示:

require.config({  baseUrl: 'scripts'});

這個配置必須放置在main.js的最前面。data-main與config配置同時存在的時候,以config為準(zhǔn),由于RJ的其它配置也是在這個位置配置的,所以4.03中的main.js可以改成如下結(jié)構(gòu),以便將來的擴(kuò)展:

require.config({  baseUrl: 'scripts'});require(['lib/foo', 'app/bar', 'app/app'], function(foo, bar, app) {  // use foo bar app do sth});

關(guān)于module ID,就是在require方法以及后續(xù)的define方法里,用在依賴數(shù)組這個參數(shù)里,用來標(biāo)識一個模塊的字符串。上面代碼中的['lib/foo', 'app/bar', 'app/app']就是一個依賴數(shù)組,其中的每個元素都是一個module ID。值得注意的是,module ID并不一定是該module 相關(guān)JS路徑的一部分,有的module ID很短,但可能路徑很長,這跟RJ的解析規(guī)則有關(guān)。下一節(jié)詳細(xì)介紹。

4.05 RJ的文件解析規(guī)則
RJ默認(rèn)按baseUrl + module ID的規(guī)則,解析文件,并且它默認(rèn)要加載的文件都是js,所以你的module ID里面可以不包含.js的后綴,這就是為啥你看到的module ID都是lib/foo, app/bar這種形式了。有三種module ID,不適用這種規(guī)則:

假如main.js如下使用:

require.config({  baseUrl: 'scripts'});require(['/lib/foo', 'test.js', '/js/jquery'], function(foo, bar, app) {  // use foo bar app do sth});

這三個module 都不會根據(jù)baseUrl + module ID的規(guī)則來解析,而是直接用module ID來解析,等效于下面的代碼:

<script src="/lib/foo.js"></script><script src="test.js"></script><script src="/js/jquery.js"></script>

各種module ID解析舉例:

例1,項(xiàng)目結(jié)構(gòu)如下:

main.js如下:

require.config({  baseUrl: 'scripts'});require(['lib/foo', 'app/bar', 'app/app'], function(foo, bar, app) {  // use foo bar app do sth});

baseUrl為:scripts目錄

moduleID為:lib/foo, app/bar, app/app

根據(jù)baseUrl + moduleID,以及自動補(bǔ)后綴.js,最終這三個module的js文件路徑為:

scripts/lib/foo.jsscripts/app/bar.jsscripts/app/app.js

例2,項(xiàng)目結(jié)構(gòu)同例1:

main.js改為:

require.config({  baseUrl: 'scripts/lib',  paths: {   app: '../app'  }});require(['foo', 'app/bar', 'app/app'], function(foo, bar, app) {  // use foo bar app do sth});

這里出現(xiàn)了一個新的配置paths,它的作用是針對module ID中特定的部分,進(jìn)行轉(zhuǎn)義,如以上代碼中對app這個部分,轉(zhuǎn)義為../app,這表示一個相對路徑,相對位置是baseUrl所指定的目錄,由項(xiàng)目結(jié)構(gòu)可知,../app其實(shí)對應(yīng)的是scirpt/app目錄。正因?yàn)橛羞@個轉(zhuǎn)義的存在,所以以上代碼中的app/bar才能被正確解析,否則還按baseUrl + moduleID的規(guī)則,app/bar不是應(yīng)該被解析成scripts/lib/app/bar.js嗎,但實(shí)際并非如此,app/bar被解析成scripts/app/bar.js,其中起關(guān)鍵作用的就是paths的配置。通過這個舉例,可以看出module ID并不一定是js文件路徑中的一部分,paths的配置對于路徑過程的js特別有效,因?yàn)榭梢院喕膍odule ID。

另外第一個模塊的ID為foo,同時沒有paths的轉(zhuǎn)義,所以根據(jù)解析規(guī)則,它的文件路徑時:scripts/lib/foo.js。

paths的配置中只有當(dāng)模塊位于baseUrl所指定的文件夾的同層目錄,或者更上層的目錄時,才會用到../這種相對路徑。

例3,項(xiàng)目結(jié)果同例1,main.js同例2:

這里要說明的問題稍微特殊,不以main.js為例,而以app.js為例,且app依賴bar,當(dāng)然config還是需要在main.js中定義的,由于這個問題在定義模塊的時候更加常見,所以用define來舉例,假設(shè)app.js模塊如下定義:

define(['./bar'], function(bar) {   return {     doSth: function() {       bar.doSth();     }   }});

上面的代碼通過define定義了一個模塊,這個define函數(shù)后面介紹如何定義模塊的時候再來介紹,這里簡單了解。這里這種用法的第一個參數(shù)跟require函數(shù)一樣,是一個依賴數(shù)組,第二個參數(shù)是一個回調(diào),也是在所有依賴加載成功之后調(diào)用,這個回調(diào)的返回值會成為這個模塊的引用被其它模塊所使用。

這里要說的問題還是跟解析規(guī)則相關(guān)的,如果完全遵守RJ的解析規(guī)則,這里的依賴應(yīng)該配置成app/bar才是正確的,但由于app.js與bar.js位于同一個目錄,所以完全可利用./這個同目錄的相對標(biāo)識符來解析js,這樣的話只要app.js已經(jīng)加載成功了,那么去同目錄下找bar.js就肯定能找到了。這種配置在定義模塊的時候非常有意義,這樣你的模塊就不依賴于放置這些模塊的文件夾名稱了。

4.06 RJ的異步加載
RJ不管是require方法還是define方法的依賴模塊都是異步加載的,所以下面的代碼不一定能解析到正確的JS文件:

<script data-main="scripts/main" src="scripts/require.js"></script><script src="scripts/other.js"></script>//main.jsrequire.config({  paths: {    foo: 'libs/foo-1.1.3'  }});//other.jsrequire( ['foo'], function( foo ) {  //foo is undefined});

由于main.js是異步加載的,所以other.js會比它先加載,但是RJ的配置存在于main.js里面,所以在加載other.js讀不到RJ的配置,在other.js執(zhí)行的時候解析出來的foo的路徑就會變成scripts/foo.js,而正確路徑應(yīng)該是scripts/libs/foo-1.1.3.js。

盡管RJ的依賴是異步加載的,但是已加載的模塊在多次依賴的時候,不會再重新加載:

define(['require', 'app/bar', 'app/app'], function(require) {  var bar= require("app/bar");  var app= require("app/app");  //use bar and app do sth});

上面的代碼,在callback定義的時候,只用了一個形參,這主要是為了減少形參的數(shù)量,避免整個回調(diào)的簽名很長。依賴的模塊在回調(diào)內(nèi)部可以直接用require(moduleID)的參數(shù)得到,由于在回調(diào)執(zhí)行前,依賴的模塊已經(jīng)加載,所以此處調(diào)用不會再重新加載。但是如果此處獲取一個并不在依賴數(shù)組中出現(xiàn)的module ID,require很有可能獲取不到該模塊引用,因?yàn)樗赡苄枰匦录虞d,如果它沒有在其它模塊中被加載過的話。

4.07 RJ官方推薦的JS文件組織結(jié)構(gòu)
RJ建議,文件組織盡量扁平,不要多層嵌套,最理想的是跟項(xiàng)目相關(guān)的放在一個文件夾,第三方庫放在一個文件夾,如下所示:

4.08 使用define定義模塊
AMD規(guī)定的模塊定義規(guī)范為:

define(id?, dependencies?, factory);其中:id: 模塊標(biāo)識,可以省略。dependencies: 所依賴的模塊,可以省略。factory: 模塊的實(shí)現(xiàn),或者一個JavaScript對象

關(guān)于第一個參數(shù),本文不會涉及,因?yàn)镽J建議所有模塊都不要使用第一個參數(shù),如果使用第一個參數(shù)定義的模塊成為命名模塊,不適用第一個參數(shù)的模塊成為匿名模塊,命名模塊如果更名,所有依賴它的模塊都得修改!第二個參數(shù)是依賴數(shù)組,跟require一樣,如果沒有這個參數(shù),那么定義的就是一個無依賴的模塊;最后一個參數(shù)是回調(diào)或者是一個簡單對象,在模塊加載完畢后調(diào)用,當(dāng)然沒有第二個參數(shù),最后一個參數(shù)也會調(diào)用。

本部分所舉例都采用如下項(xiàng)目結(jié)構(gòu):

1. 定義簡單對象模塊:

app/bar.js

define({ bar:'I am bar.'});利用main.js測試:require.config({  baseUrl: 'scripts/lib',  paths: {    app: '../app'  }});require(['app/bar'], function(bar) {  console.log(bar);// {bar: 'I am bar.'}});

2. 定義無依賴的模塊:

app/nodec.js:

define(function () {  return {    nodec: "yes, I don't need dependence."  }});

利用main.js測試:

require.config({  baseUrl: 'scripts/lib',  paths: {    app: '../app'  }});require(['app/nodec'], function(nodec) {  console.log(nodec);// {nodec: yes, I don't need dependence.'}});

3. 定義依賴其它模塊的模塊:

app/dec.js:

define(['jquery'], function($){  //use $ do sth ...  return {    useJq: true  }});

利用main.js測試:

require.config({  baseUrl: 'scripts/lib',  paths: {    app: '../app'  }});require(['app/dec'], function(dec) {  console.log(dec);//{useJq: true}});

4. 循環(huán)依賴:
當(dāng)一個模塊foo的依賴數(shù)組中存在bar,bar模塊的依賴數(shù)組中存在foo,就會形成循環(huán)依賴,稍微修改下bar.js和foo.js如下。

app/bar.js:

define(['foo'],function(foo){ return { name: 'bar', hi: function(){  console.log('Hi! ' + foo.name); } }});

lib/foo.js:

define(['app/bar'],function(bar){ return { name: 'foo', hi: function(){  console.log('Hi! ' + bar.name); } }});

利用main.js測試:

require.config({  baseUrl: 'scripts/lib',  paths: {    app: '../app'  }});require(['app/bar', 'foo'], function(bar, foo) {  bar.hi();  foo.hi();});

運(yùn)行結(jié)果:

如果改變main.js中require部分的依賴順序,結(jié)果:

循環(huán)依賴導(dǎo)致兩個依賴的module之間,始終會有一個在獲取另一個的時候,得到undefined。解決方法是,在定義module的時候,如果用到循環(huán)依賴的時候,在define內(nèi)部通過require重新獲取。main.js不變,bar.js改成:

define(['require', 'foo'], function(require, foo) {  return {    name: 'bar',    hi: function() {     foo = require('foo');      console.log('Hi! ' + foo.name);    }  }});

foo.js改成:

define(['require', 'app/bar'], function(require, bar) {  return {    name: 'foo',    hi: function() {     bar = require('app/bar');      console.log('Hi! ' + bar.name);    }  }});

利用上述代碼,重新執(zhí)行,結(jié)果是:

模塊定義總結(jié):不管模塊是用回調(diào)函數(shù)定義還是簡單對象定義,這個模塊輸出的是一個引用,所以這個引用必須是有效的,你的回調(diào)不能返回undefined,但是不局限于對象類型,還可以是數(shù)組,函數(shù),甚至是基本類型,只不過如果返回對象,你能通過這個對象組織更多的接口。

4.09 內(nèi)置的RJ模塊
再看看這個代碼:

define(['require', 'app/bar'], function(require) {  return {    name: 'foo',    hi: function() {      var bar = require('app/bar');      console.log('Hi! ' + bar.name);    }  }});

依賴數(shù)組中的require這個moduleID對應(yīng)的是一個內(nèi)置模塊,利用它加載模塊,怎么用你已經(jīng)看到了,比如在main.js中,在define中。另外一個內(nèi)置模塊是module,這個模塊跟RJ的另外一個配置有關(guān),具體用法請在第5大部分去了解。

4.10 其它RJ有用功能
1. 生成相對于模塊的URL地址

define(["require"], function(require) {  var cssUrl = require.toUrl("./style.css");});

這個功能在你想要動態(tài)地加載一些文件的時候有用,注意要使用相對路徑。

2. 控制臺調(diào)試

require("module/name").callSomeFunction()
假如你想在控制臺中查看某個模塊都有哪些方法可以調(diào)用,如果這個模塊已經(jīng)在頁面加載的時候通過依賴被加載過后,那么就可以用以上代碼在控制臺中做各種測試了。

5. RequireJS常用配置總結(jié)
在RJ的配置中,前面已經(jīng)接觸到了baseUrl,paths,另外幾個常用的配置是:

  • shim
  • config
  • enforceDefine
  • urlArgs

5.01 shim
為那些沒有使用define()來聲明依賴關(guān)系、設(shè)置模塊的"瀏覽器全局變量注入"型腳本做依賴和導(dǎo)出配置。

例1:利用exports將模塊的全局變量引用與RequireJS關(guān)聯(lián)

main.js如下:

require.config({  baseUrl: 'scripts/lib',  paths: {    app: '../app'  },  shim: {   underscore: {   exports: '_'   }  }});require(['underscore'], function(_) {  // 現(xiàn)在可以通過_調(diào)用underscore的api了});

如你所見,RJ在shim中添加了一個對underscore這個模塊的配置,并通過exports屬性指定該模塊暴露的全局變量,以便RJ能夠?qū)@些模塊統(tǒng)一管理。

例2:利用deps配置js模塊的依賴

main.js如下:

require.config({  baseUrl: 'scripts/lib',  paths: {    app: '../app'  },  shim: {   backbone: {    deps: ['underscore', 'jquery'],    exports: 'Backbone'   }  }});require(['backbone'], function(Backbone) {  //use Backbone's API});

由于backbone這個組件依賴jquery和underscore,所以可以通過deps屬性配置它的依賴,這樣backbone將會在另外兩個模塊加載完畢之后才會加載。

例3:jquery等庫插件配置方法

代碼舉例如下:

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'    }  }}); 

5.02 config
常常需要將配置信息傳給一個模塊。這些配置往往是application級別的信息,需要一個手段將它們向下傳遞給模塊。在RequireJS中,基于requirejs.config()的config配置項(xiàng)來實(shí)現(xiàn)。要獲取這些信息的模塊可以加載特殊的依賴“module”,并調(diào)用module.config()。

例1:在requirejs.config()中定義config,以供其它模塊使用

requirejs.config({  config: {    'bar': {      size: 'large'    },    'baz': {      color: 'blue'    }  }});

如你所見,config屬性中的bar這一節(jié)是在用于module ID為bar這個模塊的,baz這一節(jié)是用于module ID為baz這個模塊的。具體使用以bar.js舉例:

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

前面提到過,RJ的內(nèi)置模塊除了require還有一個module,用法就在此處,通過它可以來加載config的內(nèi)容。

5.03 enforceDefine
如果設(shè)置為true,則當(dāng)一個腳本不是通過define()定義且不具備可供檢查的shim導(dǎo)出字串值時,就會拋出錯誤。這個屬性可以強(qiáng)制要求所有RJ依賴或加載的模塊都要通過define或者shim被RJ來管理,同時它還有一個好處就是用于錯誤檢測。

5.04 urlArgs
RequireJS獲取資源時附加在URL后面的額外的query參數(shù)。作為瀏覽器或服務(wù)器未正確配置時的“cache bust”手段很有用。使用cache bust配置的一個示例:

urlArgs: "bust=" + (new Date()).getTime()
6. 錯誤處理
6.01 加載錯誤的捕獲
IE中捕獲加載錯誤不完美:

IE 6-8中的script.onerror無效。沒有辦法判斷是否加載一個腳本會導(dǎo)致404錯;更甚地,在404中依然會觸發(fā)state為complete的onreadystatechange事件。
IE 9+中script.onerror有效,但有一個bug:在執(zhí)行腳本之后它并不觸發(fā)script.onload事件句柄。因此它無法支持匿名AMD模塊的標(biāo)準(zhǔn)方法。所以script.onreadystatechange事件仍被使用。但是,state為complete的onreadystatechange事件會在script.onerror函數(shù)觸發(fā)之前觸發(fā)。
所以為了支持在IE中捕獲加載錯誤,需要配置enforceDefine為true,這不得不要求你所有的模塊都用define定義,或者用shim配置RJ對它的引用。

注意:如果你設(shè)置了enforceDefine: true,而且你使用data-main=""來加載你的主JS模塊,則該主JS模塊必須調(diào)用define()而不是require()來加載其所需的代碼。主JS模塊仍然可調(diào)用require/requirejs來設(shè)置config值,但對于模塊加載必須使用define()。比如原來的這段就會報錯:

require.config({ enforceDefine: true,  baseUrl: 'scripts/lib',  paths: {    app: '../app'  },  shim: {   backbone: {   deps: ['underscore', 'jquery'],      exports: 'Backbone'   }  }});require(['backbone'], function(Backbone) {  console.log(Backbone);});

把最后三行改成:

define(['backbone'], function(Backbone) {  console.log(Backbone);});

才不會報錯。

6.02 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'    ]  }});//Laterrequire(['jquery'], function ($) {});

上述代碼先嘗試加載CDN版本,如果出錯,則退回到本地的lib/jquery.js。

注意: paths備錯僅在模塊ID精確匹配時工作。這不同于常規(guī)的paths配置,常規(guī)配置可匹配模塊ID的任意前綴部分。備錯主要用于非常的錯誤恢復(fù),而不是常規(guī)的path查找解析,因?yàn)槟窃跒g覽器中是低效的。

6.03 全局 requirejs.onError
為了捕獲在局域的errback中未捕獲的異常,你可以重載requirejs.onError():

requirejs.onError = function (err) {  console.log(err.requireType);  if (err.requireType === 'timeout') {    console.log('modules: ' + err.requireModules);  }  throw err;};

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 英山县| 缙云县| 磐石市| 内黄县| 广汉市| 壤塘县| 昆山市| 会东县| 都安| 高唐县| 仁布县| 阿拉善右旗| 交口县| 仙游县| 武宁县| 桐城市| 手机| 美姑县| 汉中市| 尤溪县| 永吉县| 襄垣县| 基隆市| 华阴市| 彩票| 绩溪县| 德州市| 财经| 安福县| 中山市| 田东县| 巴中市| 岗巴县| 南部县| 岗巴县| 东乌珠穆沁旗| 屏东市| 左云县| 赤壁市| 大荔县| 晋州市|