Promises是一種令代碼異步行為更加優雅的抽象,它很有可能是JavaScript的下一個編程范式,一個Promise即表示任務結果,無論該任務是否完成。本文以jQuery中$.Deferred對象為例講解promise對象是如何處理異步問題,需要的朋友參考下
Promises是一種令代碼異步行為更加優雅的抽象,它很有可能是JavaScript的下一個編程范式,一個Promise即表示任務結果,無論該任務是否完成。
在一些現代瀏覽器中已經提供了原生的Promise對象,其遵循Promise/A+標準。在jQuery1.5+,提供了$.Deferred(其可以被轉化為promise對象)。很多知名的框架中,也提供了promise對象。promise對象在javascript中已經是一種很重要的模式,它在解決異步問題時表現出的優雅,正是javascript所需要的。以下以jQuery中的$.Deferred對象為例,來看一下promise對象是如何處理異步問題。關于$.Deferred對象,可以到jQuery官網查看,這里就不贅述了。
一、封裝異步操作
首先,我們以加載圖片為例,看以下代碼:
- //加載圖片函數
- var loadImg = function(url){
- var img = new Image() , deferred = $.Deferred() ;
- img.src = url ;
- img.onload = function(){
- //成功則觸發deferred.resolve
- deferred.resolve( this ) ;
- } ;
- img.onerror = function(e){
- //失敗則觸發deferred.reject
- deferred.reject( e );
- } ;
- //返回promise對象
- return deferred.promise() ;
- } ;
- //請求圖片
- var request = loadImg('http://r2.ykimg.com/0515000054AFFC2D6737B343930AFAD6') ;
- //請求成功
- request.done(function(img){
- //code
- }) ;
- //可以注冊多個回調,當請求成功時,會按注冊的順序執行,fail和always也有此性質
- request.done(function(img){
- // code
- });
- //請求失敗
- request.fail(function(){
- // code
- }) ;
- //請求完畢
- request.always(function(){
- //code
- });
以上的代碼,我封裝了圖片加載的操作,將他們委托給$.Deferred,最后生成一個promise返回。使用這樣的方式,相比用對外暴露回調的方式,顯得更干凈、更清晰。這么做的另一個更重要的原因是,promise的連接。
二、promise的連接
我們還是以上面圖片加載的代碼為例,來看一下如何做promise的連接,看以下代碼:
- var request = loadImg('http://b1.hucdn.com/upload/item/1411/13/89613257775992_800x800.jpg') ;
- request.done(function(img){
- //code
- }) ;
- //request連接別的promise之后返回的promise
- var request3 = request.then(function(img){
- //request執行成功時 連接request1
- var request1 = loadImg('http://b1.hucdn.com/upload/item/1410/19/29492535741725_800x800.jpg') ;
- return request1 ;
- },function(e){
- //request執行失敗時 連接request2
- var request2 = loadImg('http://b1.hucdn.com/upload/item/1410/19/29492535741725_800x800.jpg') ;
- return request2 ;
- });
- //request執行并且request1或request2成功執行時
- request3.done(function(done){
- //code
- }) ;
promise對象提供了then的方法,它接受兩個回調:onResolve和onReject,在回調中返回promise,就可以完成promise之間的連接。通過這種方式,可以使異步操作串行的執行。
同時,jQuery還提供了另外一種連接方式,看代碼:
- var request = loadImg('http://b1.hucdn.com/upload/item/1412/23/48188827139381_800x800.jpg') ;
- var request1 = loadImg('http://b1.hucdn.com/upload/item/1412/06/50258594673502_800x800.jpg') ;
- //通過$.when連接promise
- var request2 = $.when(request,request1) ;
- request2.done(function(img,img){
- //code
- }) ;
jQuery中提供了$.when這個函數,它可以接受n個promise對象為參數,它是將promise的執行結果連接在一起。使用這種方式,多個異步操作可以并行執行。
三、The End
這里的代碼是以加載圖片為例,同樣的做法可以應用到其他的異步操作中去。比如jQuery中的$.ajax、$.fn.animate,調用它們返回的就是promise。在node端,也可以把一些異步操作(讀數據庫、讀文件等)封裝成promise。繼而對多個promise實現合并的操作,使其串行或者并行執行。
附:deferred對象
deferred除了用于轉化promise對象外,本身也是個很有用的對象。它除了提供像promise對象的那些方法和屬性外,還有notify函數和progress函數,這兩個函數在實現進度條和瀑布流的時候,有很大的用處。
在實現進度條時,resolve和done函數可以用于定義進度條讀取到100%時的觸發時機和觸發邏輯,notify和progress函數可以用于定義進度條在讀取中的觸發時機和觸發邏輯。reject和fail函數可以用于定義進度讀取失敗時的觸發時機和觸發邏輯。
在實現瀑布流時,resolve和done函數可以用于定義當數據已經全部加載到頁面的觸發時機和觸發邏輯,notify和progress函數可以用于定義瀑布流讀取下一頁的觸發時機和觸發邏輯。
新聞熱點
疑難解答
圖片精選