日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

使用 jQuery Deferred 和 Promise 創(chuàng)建響應(yīng)式應(yīng)用程序

 昵稱13328522 2013-08-06

  這篇文章,我們一起探索一下 JavaScript 中的 Deferred 和 Promise 的概念,它們是 JavaScript 工具包(如Dojo和MochiKit)中非常重要的一個(gè)功能,最近也首次亮相于 流行的 JavaScript 庫 jQuery(已經(jīng)是1.5版本的事情了)。 Deferred 提供了一個(gè)抽象的非阻塞的解決方案(如 Ajax 請求的響應(yīng)),它創(chuàng)建一個(gè) “promise” 對象,其目的是在未來某個(gè)時(shí)間點(diǎn)返回一個(gè)響應(yīng)。如果您之前沒有接觸過 “promise”,我們將會在下面做詳細(xì)介紹。

  抽象來說,deferreds 可以理解為表示需要長時(shí)間才能完成的耗時(shí)操作的一種方式,相比于阻塞式函數(shù)它們是異步的,而不是阻塞應(yīng)用程序等待其完成然后返回結(jié)果。deferred對 象會立即返回,然后你可以把回調(diào)函數(shù)綁定到deferred對象上,它們會在異步處理完成后被調(diào)用。

Promise

  你可能已經(jīng)閱讀過一些關(guān)于promise和deferreds實(shí)現(xiàn)細(xì)節(jié)的資料。在本章節(jié)中,我們大致介紹下promise如何工作,這些在幾乎所有的支持deferreds的javascript框架中都是適用的。

  一般情況下,promise作為一個(gè)模型,提供了一個(gè)在軟件工程中描述延時(shí)(或?qū)恚└拍畹慕鉀Q方案。它背后的思想我們已經(jīng)介紹過:不是執(zhí)行一個(gè)方法然后阻塞應(yīng)用程序等待結(jié)果返回,而是返回一個(gè)promise對象來滿足未來值。

  舉一個(gè)例子會有助于理解,假設(shè)你正在建設(shè)一個(gè)web應(yīng)用程序, 它很大程度上依賴第三方api的數(shù)據(jù)。那么就會面臨一個(gè)共同的問題:我們無法獲悉一個(gè)API響應(yīng)的延遲時(shí)間,應(yīng)用程序的其他部分可能會被阻塞,直到它返回 結(jié)果。Deferreds 對這個(gè)問題提供了一個(gè)更好的解決方案,它是非阻塞的,并且與代碼完全解耦 。

  Promise/A提議’定義了一個(gè)’then‘方法來注冊回調(diào),當(dāng)處理函數(shù)返回結(jié)果時(shí)回調(diào)會執(zhí)行。它返回一個(gè)promise的偽代碼看起來是這樣的:

  1. promise = callToAPI( arg1, arg2, ...);   
  2. promise.then(function( futureValue ) {   
  3. /* handle futureValue */   
  4. });   
  5. promise.then(function( futureValue ) {  
  6.  /* do something else */  
  7.  });  

  此外,promise回調(diào)會在處于以下兩種不同的狀態(tài)下執(zhí)行:

  • resolved:在這種情況下,數(shù)據(jù)是可用
  • rejected:在這種情況下,出現(xiàn)了錯誤,沒有可用的值

  幸運(yùn)的是,'then'方法接受兩個(gè)參數(shù):一個(gè)用于promise得到了解決(resolved),另一個(gè)用于promise拒絕(rejected)。讓我們回到偽代碼:

  1. promise.then( function( futureValue ) {   
  2. /* we got a value */   
  3. } , function() {   
  4. /* something went wrong */  
  5.  } );  

  在某些情況下,我們需要獲得多個(gè)返回結(jié)果后,再繼續(xù)執(zhí)行應(yīng)用程序(例如,在用戶可以選擇他們感興趣的選項(xiàng)前,顯示一組動態(tài)的選項(xiàng))。這種情況下,'when'方法可以用來解決所有的promise都滿足后才能繼續(xù)執(zhí)行的場景。

  1. when(   
  2.   promise1,   
  3.   promise2,  
  4.    ...  
  5.  ).then(function( futureValue1, futureValue2, ... ) {   
  6.   /* all promises have completed and are resolved */  
  7.  });  

  一個(gè)很好的例子是這樣一個(gè)場景,你可能同時(shí)有多個(gè)正在運(yùn)行的動畫。 如果不跟蹤每個(gè)動畫執(zhí)行完成后的回調(diào),很難做到在動畫完成后執(zhí)行下一步任務(wù)。然而使用promise和‘when’方式卻可以很直截了當(dāng)?shù)谋硎荆?一旦動畫執(zhí)行完成,就可以執(zhí)行下一步任務(wù)。最終的結(jié)果是我們可以可以簡單的用一個(gè)回調(diào)來解決多個(gè)動畫執(zhí)行結(jié)果的等待問題。 例如:

  1. when( function(){   
  2. /* animation 1 */   
  3. /* return promise 1 */  
  4. }, function(){  
  5.  /* animation 2 */   
  6. /* return promise 2 */   
  7. } ).then(function(){  
  8.  /* once both animations have completed we can then run our additional logic */   
  9. });  

  這意味著,基本上可以用非阻塞的邏輯方式編寫代碼并異步執(zhí)行。 而不是直接將回調(diào)傳遞給函數(shù),這可能會導(dǎo)致緊耦合的接口,通過promise模式可以很容易區(qū)分同步和異步的概念。

   在下一節(jié)中,我們將著眼于jQuery實(shí)現(xiàn)的deferreds,你可能會發(fā)現(xiàn)它明顯比現(xiàn)在所看到的promise模式要簡單。

jQuery的Deferreds

  jQuery在1.5版本中首次引入了deferreds。它 所實(shí)現(xiàn)的方法與我們之前描述的抽象的概念沒有大的差別。原則上,你獲得了在未來某個(gè)時(shí)候得到‘延時(shí)’返回值的能力。在此之前是無法單獨(dú)使用的。 Deferreds 作為對ajax模塊較大重寫的一部分添加進(jìn)來,它遵循了CommonJS的promise/ A設(shè)計(jì)。1.5和先前的版本包含deferred功能,可以使$.ajax() 接收調(diào)用完成及請求出錯的回調(diào),但卻存在嚴(yán)重的耦合。開發(fā)人員通常會使用其他庫或工具包來處理延遲任務(wù)。新版本的jQuery提供了一些增強(qiáng)的方式來管理 回調(diào),提供更加靈活的方式建立回調(diào),而不用關(guān)心原始的回調(diào)是否已經(jīng)觸發(fā)。  同時(shí)值得注意的是,jQuery的遞延對象支持多個(gè)回調(diào)綁定多個(gè)任務(wù),任務(wù)本身可以既可以是同步也可以是異步的。

   您可以瀏覽下表中的遞延功能,有助于了解哪些功能是你需要的:

 

jQuery.Deferred() 創(chuàng)建一個(gè)新的Deferred對象的構(gòu)造函數(shù),可以帶一個(gè)可選的函數(shù)參數(shù),它會在構(gòu)造完成后被調(diào)用。
jQuery.when() 通過該方式來執(zhí)行基于一個(gè)或多個(gè)表示異步任務(wù)的對象上的回調(diào)函數(shù)
jQuery.ajax() 執(zhí)行異步Ajax請求,返回實(shí)現(xiàn)了promise接口的jqXHR對象
deferred.then(resolveCallback,rejectCallback) 添加處理程序被調(diào)用時(shí),遞延對象得到解決或者拒絕的回調(diào)。
deferred.done()

當(dāng)延遲成功時(shí)調(diào)用一個(gè)函數(shù)或者數(shù)組函數(shù).

deferred.fail()

當(dāng)延遲失敗時(shí)調(diào)用一個(gè)函數(shù)或者數(shù)組函數(shù).。

deferred.resolve(ARG1,ARG2,...) 調(diào)用Deferred對象注冊的‘done’回調(diào)函數(shù)并傳遞參數(shù)
deferred.resolveWith(context,args) 調(diào)用Deferred對象注冊的‘done’回調(diào)函數(shù)并傳遞參數(shù)和設(shè)置回調(diào)上下文
deferred.isResolved 確定一個(gè)Deferred對象是否已經(jīng)解決。
deferred.reject(arg1,arg2,...) 調(diào)用Deferred對象注冊的‘fail’回調(diào)函數(shù)并傳遞參數(shù)
deferred.rejectWith(context,args) 調(diào)用Deferred對象注冊的‘fail’回調(diào)函數(shù)并傳遞參數(shù)和設(shè)置回調(diào)上下文
deferred.promise() 返回promise對象,這是一個(gè)偽造的deferred對象:它基于deferred并且不能改變狀態(tài)所以可以被安全的傳遞

 

  jQuery延時(shí)實(shí)現(xiàn)的核心是jQuery.Deferred:一個(gè)可以鏈?zhǔn)秸{(diào)用的構(gòu)造函數(shù)。...... 需要注意的是任何deferred對象的默認(rèn)狀態(tài)是unresolved, 回調(diào)會通過 .then() 或 .fail()方法添加到隊(duì)列,并在稍后的過程中被執(zhí)行。  

  下面這個(gè)$.when() 接受多個(gè)參數(shù)的例子  

  1. function successFunc(){ console.log( “success!” ); }   
  2. function failureFunc(){ console.log( “failure!” ); }   
  3.   
  4. $.when(   
  5.    $.ajax( "/main.php" ),  
  6.    $.ajax( "/modules.php" ),  
  7.    $.ajax( “/lists.php” )  
  8.  ).then( successFunc, failureFunc );   

  在$.when() 的實(shí)現(xiàn)中有趣的是,它并非僅能解析deferred對象,還可以傳遞不是deferred對象的參數(shù),在處理的時(shí)候會把它們當(dāng)做deferred對象并立 即執(zhí)行回調(diào)(doneCallbacks)。 這也是jQuery的Deferred實(shí)現(xiàn)中值得一提的地方,此外,deferred.then()還為deferred.done和 deferred.fail()方法在deferred的隊(duì)列中增加回調(diào)提供支持。

  利用前面介紹的表中提到的deferred功能,我們來看一個(gè)代碼示例。 在這里,我們創(chuàng)建一個(gè)非?;镜膽?yīng)用程序:通過$.get方法(返回一個(gè)promise)獲取一條外部新聞源(1)并且(2)獲取最新的一條回復(fù)。  同時(shí)程序還通過函數(shù)(prepareInterface())實(shí)現(xiàn)新聞和回復(fù)內(nèi)容顯示容器的動畫。

  為了確保在執(zhí)行其他相關(guān)行為前,上面的這三個(gè)步驟確保完成,我們使用$.when()。根據(jù)您的需要 .then()和.fail() 處理函數(shù)可以被用來執(zhí)行其他程序邏輯。

  1. function getLatestNews() {   
  2.   return $.get( “l(fā)atestNews.php”, function(data){   
  3.      console.log( “news data received” );   
  4.      $( “.news” ).html(data);   
  5.    } );  
  6.  }  
  7.  function getLatestReactions() {  
  8.     return $.get( “l(fā)atestReactions.php”, function(data){   
  9.        console.log( “reactions data received” );  
  10.        $( “.reactions” ).html(data);  
  11.     } );  
  12.  }  
  13.   
  14. function prepareInterface() {   
  15.    return $.Deferred(function( dfd ) {   
  16.        var latest = $( “.news, .reactions” );  
  17.        latest.slideDown( 500, dfd.resolve );  
  18.        latest.addClass( “active” );  
  19.     }).promise();   
  20. }   
  21.   
  22. $.when(   
  23.     getLatestNews(), getLatestReactions(), prepareInterface()  
  24.  ).then(function(){   
  25.     console.log( “fire after requests succeed” );  
  26.  }).fail(function(){   
  27.     console.log( “something went wrong!” );  
  28.  });   

  deferreds在ajax的幕后操作中使用并不意味著它們無法在別處使用。 在本節(jié)中,我們將看到在一些解決方案中,使用deferreds將有助于抽象掉異步的行為,并解耦我們的代碼。

異步緩存

  當(dāng)涉及到異步任務(wù),緩存可以是一個(gè)有點(diǎn)苛刻的,因?yàn)槟惚仨毚_保對于同一個(gè)key任務(wù)僅執(zhí)行一次。因此,代碼需要以某種方式跟蹤入站任務(wù)。 例如下面的代碼片段:

  1. $.cachedGetScript( url, callback1 );   
  2. $.cachedGetScript( url, callback2 );  

  緩存機(jī)制需要確保 腳本不管是否已經(jīng)存在于緩存,只能被請求一次。 因此,為了緩存系統(tǒng)可以正確地處理請求,我們最終需要寫出一些邏輯來跟蹤綁定到給定url上的回調(diào)。

  值得慶幸的是,這恰好是deferred所實(shí)現(xiàn)的那種邏輯,因此我們可以這樣來做:

  1. var cachedScriptPromises = {};   
  2. $.cachedGetScript = function( url, callback ) {  
  3.      if ( !cachedScriptPromises[ url ] ) {   
  4.         cachedScriptPromises[ url ] = $.Deferred(function( defer ) {  
  5.             $.getScript( url ).then( defer.resolve, defer.reject );   
  6.         }).promise();   
  7.     }  
  8.     return cachedScriptPromises[ url ].done( callback );  
  9. };  

  代碼相當(dāng)簡單:我們?yōu)槊恳粋€(gè)url緩存一個(gè)promise對象。 如果給定的url沒有promise,我們創(chuàng)建一個(gè)deferred,并發(fā)出請求。 如果它已經(jīng)存在我們只需要為它綁定回調(diào)。 該解決方案的一大優(yōu)勢是,它會透明地處理新的和緩存過的請求。 另一個(gè)優(yōu)點(diǎn)是一個(gè)基于deferred的緩存 會優(yōu)雅地處理失敗情況。 當(dāng)promise以‘rejected’狀態(tài)結(jié)束的話,我們可以提供一個(gè)錯誤回調(diào)來測試:

  $.cachedGetScript( url ).then( successCallback, errorCallback );

  請記?。簾o論請求是否緩存過,上面的代碼段都會正常運(yùn)作!

通用異步緩存

  為了使代碼盡可能的通用,我們建立一個(gè)緩存工廠并抽象出實(shí)際需要執(zhí)行的任務(wù)??:

  1. $.createCache = function( requestFunction ) {   
  2.     var cache = {};   
  3.     return function( key, callback ) {   
  4.         if ( !cache[ key ] ) {   
  5.             cache[ key ] = $.Deferred(function( defer ) {  
  6.                 requestFunction( defer, key );  
  7.              }).promise();   
  8.         }   
  9.         return cache[ key ].done( callback );  
  10.     };   
  11. }   

  現(xiàn)在具體的請求邏輯已經(jīng)抽象出來,我們可以重新寫cachedGetScript:

  1. $.cachedGetScript = $.createCache(function( defer, url ) {  
  2.       $.getScript( url ).then( defer.resolve, defer.reject );  
  3.  });  

  每次調(diào)用createCache將創(chuàng)建一個(gè)新的緩存庫,并返回一個(gè)新的高速緩存檢索函數(shù)?,F(xiàn)在,我們擁有了一個(gè)通用的緩存工廠,它很容易實(shí)現(xiàn)涉及從緩存中取值的邏輯場景。

圖片加載

  另一個(gè)候選場景是圖像加載:確保我們不加載同一個(gè)圖像兩次,我們可能需要加載圖像。 使用createCache很容易實(shí)現(xiàn):

  1. $.loadImage = $.createCache(function( defer, url ) {   
  2.     var image = new Image();  
  3.      function cleanUp() {  
  4.         image.onload = image.onerror = null;   
  5.     }  
  6.      defer.then( cleanUp, cleanUp );  
  7.      image.onload = function() {   
  8.         defer.resolve( url );   
  9.     };   
  10.     image.onerror = defer.reject;   
  11.     image.src = url;  
  12.  });  

  接下來的代碼片段如下:

  1. $.loadImage( "my-image.png" ).done( callback1 );   
  2. $.loadImage( "my-image.png" ).done( callback2 );   

  無論image.png是否已經(jīng)被加載,或者正在加載過程中,緩存都會正常工作。

緩存數(shù)據(jù)的API響應(yīng)

  哪些你的頁面的生命周期過程中被認(rèn)為是不可變的API請求,也是緩存完美的候選場景。 比如,執(zhí)行以下操作:

  1. $.searchTwitter = $.createCache(function( defer, query ) {   
  2.     $.ajax({   
  3.         url: "http://search.twitter.com/search.json",   
  4.         data: { q: query },   
  5.         dataType: "jsonp",   
  6.         success: defer.resolve,   
  7.         error: defer.reject   
  8.     });   
  9. });  

  程序允許你在Twitter上進(jìn)行搜索,同時(shí)緩存它們:

  1. $.searchTwitter( "jQuery Deferred", callback1 );   
  2. $.searchTwitter( "jQuery Deferred", callback2 );  

定時(shí)

  基于deferred的緩存并不限定于網(wǎng)絡(luò)請求;它也可以被用于定時(shí)目的。

  例如,您可能需要在網(wǎng)頁上給定一段時(shí)間后執(zhí)行一個(gè)動作,來吸引用戶對某個(gè)不容易引起注意的特定功能的關(guān)注或處理一個(gè)延時(shí)問題。 雖然setTimeout適合大多數(shù)用例,但在計(jì)時(shí)器出發(fā)后甚至理論上過期后就無法提供解決辦法。 我們可以使用以下的緩存系統(tǒng)來處理:

  1. var readyTime;   
  2. $(function() { readyTime = jQuery.now(); });   
  3. $.afterDOMReady = $.createCache(function( defer, delay ) {   
  4.     delay = delay || 0;   
  5.     $(function() {  
  6.         var delta = $.now() - readyTime;   
  7.         if ( delta >= delay ) { defer.resolve(); }   
  8.         else {   
  9.             setTimeout( defer.resolve, delay - delta );  
  10.          }   
  11.     });   
  12. });  

  新的afterDOMReady輔助方法用最少的計(jì)數(shù)器提供了domReady后的適當(dāng)時(shí)機(jī)。 如果延遲已經(jīng)過期,回調(diào)會被馬上執(zhí)行。

同步多個(gè)動畫

  動畫是另一個(gè)常見的異步任務(wù)范例。 然而在幾個(gè)不相關(guān)的動畫完成后執(zhí)行代碼仍然有點(diǎn)挑戰(zhàn)性。盡管在jQuery1.6中才提供了在動畫元素上取得promise對象的功能,但它是很容易的手動實(shí)現(xiàn):

  1. $.fn.animatePromise = function( prop, speed, easing, callback ) {   
  2.     var elements = this;   
  3.     return $.Deferred(function( defer ) {   
  4.         elements.animate( prop, speed, easing, function() {   
  5.         defer.resolve();   
  6.         if ( callback ) {   
  7.         callback.apply( this, arguments );  
  8.          }   
  9.         });   
  10.     }).promise();  
  11. };  

   然后,我們可以使用$.when()同步化不同的動畫:

  1. var fadeDiv1Out = $( "#div1" ).animatePromise({ opacity: 0 }),   
  2.       fadeDiv2In = $( "#div1" ).animatePromise({ opacity: 1 }, "fast" );   
  3.   
  4. $.when( fadeDiv1Out, fadeDiv2In ).done(function() {   
  5.      /* both animations ended */  
  6.  });  

  我們也可以使用同樣的技巧,建立了一些輔助方法:

  1. $.each([ "slideDown""slideUp""slideToggle""fadeIn""fadeOut""fadeToggle" ],   
  2. function( _, name ) {   
  3.     $.fn[ name + "Promise" ] = function( speed, easing, callback ) {  
  4.         var elements = this;   
  5.         return $.Deferred(function( defer ) {   
  6.             elements[ name ]( speed, easing, function() {   
  7.                 defer.resolve();   
  8.                 if ( callback ) {   
  9.                 callback.apply( this, arguments );   
  10.                 }   
  11.             });  
  12.          }).promise();   
  13.     };   
  14. });  

  然后想下面這樣使用新的助手代碼來同步動畫:

  1. $.when(   
  2.     $( "#div1" ).fadeOutPromise(),   
  3.     $( "#div2" ).fadeInPromise( "fast" )   
  4. ).done(function() {  
  5.     /* both animations are done */  
  6.  });  
  7.    

一次性事件

  雖然jQuery提供你可能需要的所有的時(shí)間綁定方法,但當(dāng)事件僅需要處理一次時(shí),情況可能會變得有點(diǎn)棘手。( 與$.one() 不同 ) 

  例如,您可能希望有一個(gè)按鈕,當(dāng)它第一次被點(diǎn)擊時(shí)打開一個(gè)面板,面板打開之后,執(zhí)行特定的初始化邏輯。 在處理這種情況時(shí),人們通常會這樣寫代碼:

  1. var buttonClicked = false;   
  2. $( "#myButton" ).click(function() {   
  3.     if ( !buttonClicked ) {   
  4.         buttonClicked = true;   
  5.         initializeData();   
  6.         showPanel();   
  7.     }   
  8. });  

  不久后,你可能會在面板打開之后點(diǎn)擊按鈕時(shí)添加一些操作,如下:

  1. if ( buttonClicked ) { /* perform specific action */ }  

  這是一個(gè)非常耦合的解決辦法。 如果你想添加一些其他的操作,你必須編輯綁定代碼或拷貝一份。 如果你不這樣做,你唯一的選擇是測試buttonClicked。由于buttonClicked可能是false,新的代碼可能永遠(yuǎn)不會被執(zhí)行,因此你 可能會失去這個(gè)新的動作。

  使用deferreds我們可以做的更好 (為簡化起見,下面的代碼將只適用于一個(gè)單一的元素和一個(gè)單一的事件類型,但它可以很容易地?cái)U(kuò)展為多個(gè)事件類型的集合):

  1. $.fn.bindOnce = function( event, callback ) {   
  2.     var element = $( this[ 0 ] ),   
  3.     defer = element.data( "bind_once_defer_" + event );   
  4.     if ( !defer ) {   
  5.         defer = $.Deferred();   
  6.         function deferCallback() {   
  7.             element.unbind( event, deferCallback );   
  8.             defer.resolveWith( this, arguments );   
  9.         }   
  10.         element.bind( event, deferCallback )   
  11.         element.data( "bind_once_defer_" + event , defer );   
  12.     }   
  13.     return defer.done( callback ).promise();   
  14. };  

  該代碼的工作原理如下:

  • 檢查該元素是否已經(jīng)綁定了一個(gè)給定事件的deferred對象
  • 如果沒有,創(chuàng)建它,使它在觸發(fā)該事件的第一時(shí)間解決
  • 然后在deferred上綁定給定的回調(diào)并返回promise

  代碼雖然很冗長,但它會簡化相關(guān)問題的處理。 讓我們先定義一個(gè)輔助方法:

  1. $.fn.firstClick = function( callback ) {   
  2.        return this.bindOnce( "click", callback );  
  3.  };  

  然后,之前的邏輯可以重構(gòu)如下:

  1. var openPanel = $( "#myButton" ).firstClick();   
  2. openPanel.done( initializeData );   
  3. openPanel.done( showPanel );  

  如果我們需要執(zhí)行一些動作,只有當(dāng)面板打開以后,所有我們需要的是這樣的:

  1. openPanel.done(function() { /* perform specific action */ });     

  如果面板沒有打開,行動將得到延遲到單擊該按鈕時(shí)。

組合助手

  單獨(dú)看以上每個(gè)例子,promise的作用是有限的 。 然而,promise真正的力量是把它們混合在一起。

 

在第一次點(diǎn)擊時(shí)加載面板內(nèi)容并打開面板

  假如,我們有一個(gè)按鈕,可以打開一個(gè)面板,請求其內(nèi)容然后淡入內(nèi)容。使用我們前面定義的助手方法,我們可以這樣做:

  1. var panel = $( "#myPanel" );   
  2. panel.firstClick(function() {    
  3.     $.when(   
  4.         $.get( "panel.html" ),   
  5.         panel.slideDownPromise()  
  6.     ).done(function( ajaxResponse ) {   
  7.         panel.html( ajaxResponse[ 0 ] ).fadeIn();   
  8.     });  
  9. });  

在第一次點(diǎn)擊時(shí)載入圖像并打開面板

  假如,我們已經(jīng)的面板有內(nèi)容,但我們只希望當(dāng)?shù)谝淮螁螕舭粹o時(shí)加載圖像并且當(dāng)所有圖像加載成功后淡入圖像。HTML代碼如下:

  1. <div id="myPanel">   
  2. <img data-src="image1.png" />  
  3.  <img data-src="image2.png" />  
  4.  <img data-src="image3.png" />   
  5. <img data-src="image4.png" />   
  6. </div>  

  我們使用data-src屬性描述圖片的真實(shí)路徑。 那么使用promise助手來解決該用例的代碼如下:

  1. $( "#myButton" ).firstClick(function() {   
  2.     var panel = $( "#myPanel" ),   
  3.     promises = [];   
  4.     $( "img", panel ).each(function() {   
  5.         var image = $( this ), src = element.attr( "data-src" );   
  6.         if ( src ) {   
  7.         promises.push(   
  8.             $.loadImage( src ).then( function() {  
  9.                     image.attr( "src", src );   
  10.                 }, function() {   
  11.                     image.attr( "src""error.png" );  
  12.             } )   
  13.         );  
  14.         }   
  15.     });   
  16.   
  17.     promises.push( panel.slideDownPromise() );   
  18.   
  19.     $.when.apply( null, promises ).done(function() { panel.fadeIn(); });   
  20. });  

  這里的竅門是跟蹤所有的LoadImage 的promise,接下來加入面板slideDown動畫。 因此首次點(diǎn)擊按鈕時(shí),面板將slideDown并且圖像將開始加載。 一旦完成向下滑動面板和已加載的所有圖像,面板才會淡入。

在特定延時(shí)后加載頁面上的圖像

  假如,我們要在整個(gè)頁面實(shí)現(xiàn)遞延圖像顯示。 要做到這一點(diǎn),我們需要的HTML的格式如下:

  1. <img data-src="image1.png" data-after="1000" src="placeholder.png" />   
  2. <img data-src="image2.png" data-after="1000" src="placeholder.png" />   
  3. <img data-src="image1.png" src="placeholder.png" />   
  4. <img data-src="image2.png" data-after="2000" src="placeholder.png" />  

  意思非常簡單:

  • image1.png,第三個(gè)圖像立即顯示,一秒后第一個(gè)圖像顯示
  • image2.png 一秒鐘后顯示第二個(gè)圖像,兩秒鐘后顯示第四個(gè)圖像

  我們將如何實(shí)現(xiàn)呢?

  1. $( "img" ).each(function() {  
  2.     var element = $( this ),  
  3.         src = element.attr( "data-src" ),  
  4.         after = element.attr( "data-after" );  
  5.     if ( src ) {  
  6.         $.when(  
  7.             $.loadImage( src ),  
  8.             $.afterDOMReady( after )  
  9.         ).then(function() {  
  10.             element.attr( "src", src );  
  11.         }, function() {  
  12.             element.attr( "src""error.png" );  
  13.         } ).done(function() {  
  14.             element.fadeIn();  
  15.         });  
  16.     }  
  17. });  

   如果我們想延遲加載的圖像本身,代碼會有所不同:

  1. $( "img" ).each(function() {  
  2.     var element = $( this ),  
  3.         src = element.attr( "data-src" ),  
  4.         after = element.attr( "data-after" );  
  5.     if ( src ) {  
  6.         $.afterDOMReady( after, function() {  
  7.             $.loadImage( src ).then(function() {  
  8.                 element.attr( "src", src );  
  9.             }, function() {  
  10.                 element.attr( "src""error.png" );  
  11.             } ).done(function() {  
  12.                 element.fadeIn();  
  13.             });  
  14.         } );  
  15.     }  
  16. });  

  這里,我們首先在嘗試加載圖片之前等待延遲條件滿足。當(dāng)你想在頁面加載時(shí)限制網(wǎng)絡(luò)請求的數(shù)量會非常有意義。

結(jié)論

  正如你看到的,即使在沒有Ajax請求的情況下,promise也非常有用的。通過使用jQuery 1.5中的deferred實(shí)現(xiàn) ,會非常容易的從你的代碼中分離出異步任務(wù)。 這樣的話,你可以很容易的從你的應(yīng)用程序中分離邏輯。

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多