亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 語言 > JavaScript > 正文

異步JavaScript編程中的Promise使用方法

2024-05-06 16:23:57
字體:
來源:轉載
供稿:網友

這篇文章主要介紹了異步JavaScript編程中的Promise使用方法,包含Ajax的結合操作等問題,需要的朋友可以參考下

異步?

我在很多地方都看到過異步(Asynchronous)這個詞,但在我還不是很理解這個概念的時候,卻發現自己常常會被當做“已經很清楚”(* ̄? ̄)。

如果你也有類似的情況,沒關系,搜索一下這個詞,就可以得到大致的說明。在這里,我會對JavaScript的異步做一點額外解釋。

看一下這段代碼:

 

 
  1. var start = new Date(); 
  2. setTimeout(function(){ 
  3. var end = new Date(); 
  4. console.log("Time elapsed: ", end - start, "ms"); 
  5. }, 500); 
  6. while (new Date - start < 1000) {}; 

這段代碼運行后會得到類似Time elapsed: 1013ms這樣的結果。 setTimeout()所設定的在未來500ms時執行的函數,實際等了比1000ms更多的時間后才執行。

要如何解釋呢?調用setTimeout()時,一個延時事件被排入隊列。然后,繼續執行這之后的代碼,以及更后邊的代碼,直到沒有任何代碼。沒有任何代碼后,JavaScript線程進入空閑,此時JavaScript執行引擎才去翻看隊列,在隊列中找到“應該觸發”的事件,然后調用這個事件的處理器(函數)。處理器執行完成后,又再返回到隊列,然后查看下一個事件。

單線程的JavaScript,就是這樣通過隊列,以事件循環的形式工作的。所以,前面的代碼中,是用while將執行引擎拖在代碼運行期間長達1000ms,而在全部代碼運行完回到隊列前,任何事件都不會觸發。這就是JavaScript的異步機制。

JavaScript的異步難題

JavaScript中的異步操作可能不總是簡單易行的。

Ajax也許是我們用得最多的異步操作。以jQuery為例,發起一個Ajax請求的代碼一般是這樣的:

 

 
  1. // Ajax請求示意代碼 
  2. $.ajax({ 
  3. url: url, 
  4. data: dataObject, 
  5. success: function(){}, 
  6. error: function(){} 
  7. }); 

這樣的寫法有什么問題嗎?簡單來說,不夠輕便。為什么一定要在發起請求的地方,就要把success和error這些回調給寫好呢?假如我的回調要做很多很多的事情,是要我想起一件事情就跑回這里添加代碼嗎?

再比如,我們要完成這樣一件事:有4個供Ajax訪問的url地址,需要先Ajax訪問第1個,在第1個訪問完成后,用拿到的返回數據作為參數再訪問第2個,第2個訪問完成后再第3個...以此到4個全部訪問完成。按照這樣的寫法,似乎會變成這樣:

 

 
  1. $.ajax({ 
  2. url: url1, 
  3. success: function(data){ 
  4. $.ajax({ 
  5. url: url2, 
  6. data: data, 
  7. success: function(data){ 
  8. $.ajax({ 
  9. //... 
  10. }); 
  11. }  
  12. }); 
  13. }) 

你一定會覺得這種稱為Pyramid of Doom(金字塔厄運)的代碼看起來很糟糕。習慣了直接附加回調的寫法,就可能會對這種一個傳遞到下一個的異步事件感到無從入手。為這些回調函數分別命名并分離存放可以在形式上減少嵌套,使代碼清晰,但仍然不能解決問題。

另一個常見的難點是,同時發送兩個Ajax請求,然后要在兩個請求都成功返回后再做一件接下來的事,想一想如果只按前面的方式在各自的調用位置去附加回調,這是不是好像也有點難辦?

適于應對這些異步操作,可以讓你寫出更優雅代碼的就是Promise。

Promise上場

Promise是什么呢?先繼續以前面jQuery的Ajax請求示意代碼為例,那段代碼其實可以寫成這個樣子:

 

 
  1. var promise = $.ajax({ 
  2. url: url, 
  3. data: dataObject 
  4. }); 
  5. promise.done(function(){}); 
  6. promise.fail(function(){}); 

這和前面的Ajax請求示意代碼是等效的??梢钥吹剑琍romise的加入使得代碼形式發生了變化。Ajax請求就好像變量賦值一樣,被“保存”了起來。這就是封裝,封裝將真正意義上讓異步事件變得容易起來。

封裝是有用的

Promise對象就像是一個封裝好的對異步事件的引用。想要在這個異步事件完成后做點事情?給它附加回調就可以了,不管附加多少個也沒問題!

jQuery的Ajax方法會返回一個Promise對象(這是jQuery1.5重點增加的特性)。如果我有do1()、do2()兩個函數要在異步事件成功完成后執行,只需要這樣做:

 

  1. promise.done(do1); 
  2. // Other code here. 
  3. promise.done(do2); 

這樣可要自由多了,我只要保存這個Promise對象,就在寫代碼的任何時候,給它附加任意數量的回調,而不用管這個異步事件是在哪里發起的。這就是Promise的優勢。

正式的介紹

Promise應對異步操作是如此有用,以至于發展為了CommonJS的一個規范,叫做Promises/A。Promise代表的是某一操作結束后的返回值,它有3種狀態:

肯定(fulfilled或resolved),表明該Promise的操作成功了。

否定(rejected或failed),表明該Promise的操作失敗了。

等待(pending),還沒有得到肯定或者否定的結果,進行中。

此外,還有1種名義上的狀態用來表示Promise的操作已經成功或失敗,也就是肯定和否定狀態的集合,叫做結束(settled)。Promise還具有以下重要的特性:

一個Promise只能從等待狀態轉變為肯定或否定狀態一次,一旦轉變為肯定或否定狀態,就再也不會改變狀態。

如果在一個Promise結束(成功或失敗,同前面的說明)后,添加針對成功或失敗的回調,則回調函數會立即執行。

想想Ajax操作,發起一個請求后,等待著,然后成功收到返回或出現錯誤(失敗)。這是否和Promise相當一致?

進一步解釋Promise的特性還有一個很好的例子:jQuery的$(document).ready(onReady)。其中onReady回調函數會在DOM就緒后執行,但有趣的是,如果在執行到這句代碼之前,DOM就已經就緒了,那么onReady會立即執行,沒有任何延遲(也就是說,是同步的)。

Promise示例 生成Promise

Promises/A里列出了一系列實現了Promise的JavaScript庫,jQuery也在其中。下面是用jQuery生成Promise的代碼:

 

 
  1. var deferred = $.Deferred(); 
  2. deferred.done(function(message){console.log("Done: " + message)}); 
  3. deferred.resolve("morin"); // Done: morin 

jQuery自己特意定義了名為Deferred的類,它實際上就是Promise。$.Deferred()方法會返回一個新生成的Promise實例。一方面,使用deferred.done()、deferred.fail()等為它附加回調,另一方面,調用deferred.resolve()或deferred.reject()來肯定或否定這個Promise,且可以向回調傳遞任意數據。

合并Promise

還記得我前文說的同時發送2個Ajax請求的難題嗎?繼續以jQuery為例,Promise將可以這樣解決它:

 

 
  1. var promise1 = $.ajax(url1), 
  2. promise2 = $.ajax(url2), 
  3. promiseCombined = $.when(promise1, promise2); 
  4. promiseCombined.done(onDone); 

$.when()方法可以合并多個Promise得到一個新的Promise,相當于在原多個Promise之間建立了AND(邏輯與)的關系,如果所有組成Promise都已成功,則令合并后的Promise也成功,如果有任意一個組成Promise失敗,則立即令合并后的Promise失敗。

級聯Promise

再繼續我前文的依次執行一系列異步任務的問題。它將用到Promise最為重要的.then()方法(在Promises/A規范中,也是用“有then()方法的對象”來定義Promise的)。代碼如下:

 

 
  1. var promise = $.ajax(url1); 
  2. promise = promise.then(function(data){ 
  3. return $.ajax(url2, data); 
  4. }); 
  5. promise = promise.then(function(data){ 
  6. return $.ajax(url3, data); 
  7. }); 
  8. // ... 

Promise的.then()方法的完整形式是.then(onDone, onFail, onProgress),這樣看上去,它像是一個一次性就可以把各種回調都附加上去的簡便方法(.done()、.fail()可以不用了)。沒錯,你的確可以這樣使用,這是等效的。

但.then()方法還有它更為有用的功能。如同then這個單詞本身的意義那樣,它用來清晰地指明異步事件的前后關系:“先這個,然后(then)再那個”。這稱為Promise的級聯。

要級聯Promise,需要注意的是,在傳遞給then()的回調函數中,一定要返回你想要的代表下一步任務的Promise(如上面代碼的$.ajax(url2, data))。這樣,前面被賦值的那個變量才會變成新的Promise。而如果then()的回調函數返回的不是Promise,則then()方法會返回最初的那個Promise。

應該會覺得有些難理解?從代碼執行的角度上說,上面這段帶有多個then()的代碼其實還是被JavaScript引擎運行一遍就結束。但它就像是寫好的舞臺劇的劇本一樣,讀過一遍后,JavaScript引擎就會在未來的時刻,依次安排演員按照劇本來演出,而演出都是異步的。then()方法就是讓你能寫出異步劇本的筆。

將Promise用在基于回調函數的API

前文反復用到的$.ajax()方法會返回一個Promise對象,這其實只是jQuery特意提供的福利。實際情況是,大多數JavaScript API,包括Node.js中的原生函數,都基于回調函數,而不是基于Promise。這種情況下使用Promise會需要自行做一些加工。

這個加工其實比較簡單和直接,下面是例子:

 

 
  1. var deferred = $.Deferred(); 
  2. setTimeout(deferred.resolve, 1000); 
  3. deferred.done(onDone); 

這樣,將Promise的肯定或否定的觸發器,作為API的回調傳入,就變成了Promise的處理模式了。

Promise是怎么實現出來的?

本文寫Promise寫到這里,你發現了全都是基于已有的實現了Promise的庫。那么,如果要自行構筑一個Promise的話呢?

位列于Promises/A的庫列表第一位的Q可以算是最符合Promises/A規范且相當直觀的實現。如果你想了解如何做出一個Promise,可以參考Q提供的設計模式解析。

限于篇幅,本文只介紹Promise的應用。我會在以后單獨開一篇文章來詳述Promise的實現細節。

作為JavaScript后續版本的ECMAScript 6將原生提供Promise,如果你想知道它的用法,推薦閱讀JavaScript Promises: There and back again。

結語

Promise這個詞頑強到不適合翻譯,一眼之下都會覺得意義不明。不過,在JavaScript里做比較復雜的異步任務時,它的確可以提供相當多的幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品激情av电影在线观看| 在线观看精品国产视频| 成人国产精品日本在线| 狠狠久久亚洲欧美专区| 久久久99免费视频| 欧美一级淫片aaaaaaa视频| 精品视频在线观看日韩| 欧美激情久久久久| 欧美精品福利视频| 精品久久久视频| 国产不卡一区二区在线播放| 插插插亚洲综合网| 狠狠色狠狠色综合日日五| 国产一区二区三区在线免费观看| 欧美日韩国产色| 精品高清一区二区三区| 国产精品一区二区三| 久久免费视频这里只有精品| 欧美日韩国产在线看| 国产伦精品免费视频| 成人欧美一区二区三区黑人孕妇| 欧美性xxxxxx| 日韩亚洲第一页| 亚洲精品电影网| 国产一区二区久久精品| 第一福利永久视频精品| 欧美成人精品一区二区三区| 亚洲影院污污.| 欧美激情在线观看| 日本午夜精品理论片a级appf发布| 久久精品国产成人| 亚洲美腿欧美激情另类| 亚洲午夜精品久久久久久久久久久久| 国产精品久久久久久超碰| 欧美国产亚洲精品久久久8v| 欧美裸体男粗大视频在线观看| 黑人巨大精品欧美一区二区免费| 久久夜色精品国产| 亚洲免费高清视频| 精品久久久久久久久国产字幕| 伊人激情综合网| 欧洲s码亚洲m码精品一区| 国产欧美日韩中文| 中文字幕免费国产精品| 亚洲综合在线播放| 狠狠做深爱婷婷久久综合一区| 疯狂做受xxxx高潮欧美日本| 国产精品第二页| 高清一区二区三区四区五区| 欧美—级a级欧美特级ar全黄| 国产精品美女免费| 丁香五六月婷婷久久激情| 91精品国产综合久久香蕉922| 国产美女精品视频| 日韩黄色av网站| 国产成人综合精品在线| 亚洲国产精品字幕| 国产亚洲欧美aaaa| 91国产在线精品| 深夜福利日韩在线看| 亚洲成在人线av| 国产精品99蜜臀久久不卡二区| 2020国产精品视频| 中文字幕亚洲激情| 久久久久国色av免费观看性色| 成人免费福利视频| 国产精品69精品一区二区三区| 亚洲欧美激情精品一区二区| 91精品在线影院| 91a在线视频| 精品久久久久久亚洲国产300| 欧美性在线视频| 国产婷婷色综合av蜜臀av| 91极品视频在线| 这里只有精品在线观看| 成人夜晚看av| 久久久久久久999| 国产成人综合亚洲| 亚洲欧美综合v| 欧美性猛交xxxx免费看久久久| 国产精品高清网站| 欧美日韩性视频在线| 久久久久久国产| 91免费电影网站| 国产精品久久久久99| 国产精品第一第二| 日韩中文字幕不卡视频| 亚洲第一精品久久忘忧草社区| 国产精品三级久久久久久电影| 欧美日韩一区二区在线播放| 精品中文字幕在线观看| 91中文在线观看| 97在线视频观看| 欧美日韩综合视频网址| 蜜月aⅴ免费一区二区三区| 欧美一区二区三区图| 国产主播精品在线| 97成人精品视频在线观看| 欧美日产国产成人免费图片| 日韩一区二区精品视频| 国产精品中文字幕在线| 久久中文久久字幕| 国产精品国产福利国产秒拍| 欧美激情一区二区三区在线视频观看| 日韩精品中文字幕在线| 色偷偷偷综合中文字幕;dd| 日本久久久久久| 精品国产依人香蕉在线精品| 欧美国产一区二区三区| 精品视频—区二区三区免费| 成人午夜在线观看| 国产精品高清免费在线观看| 国产精品欧美亚洲777777| 国产精品久久久久久久午夜| 亚洲欧洲在线播放| 尤物99国产成人精品视频| 成人免费网站在线观看| 亚洲国产小视频在线观看| 亚洲网站视频福利| 69av在线播放| 成人亚洲激情网| 久久久国产一区| 夜夜狂射影院欧美极品| 国产成人精品视频在线观看| 国产精品91一区| 日韩中文字幕精品视频| 欧美一区二区三区图| 97成人精品区在线播放| 欧美性受xxxx白人性爽| 色婷婷**av毛片一区| 国产精品免费视频xxxx| 亚洲国产精品国自产拍av秋霞| 亚洲毛茸茸少妇高潮呻吟| 久久韩国免费视频| 久久久免费高清电视剧观看| 久久免费视频观看| 国产不卡av在线免费观看| 日韩中文视频免费在线观看| 亚洲女人被黑人巨大进入al| 久久国产精品久久久久久| 精品久久久精品| 在线免费看av不卡| 波霸ol色综合久久| 欧美亚洲另类视频| 在线观看国产精品淫| 九九热这里只有精品免费看| 在线精品播放av| 日韩av综合中文字幕| 成人福利视频在线观看| 成人高h视频在线| 亚洲精品之草原avav久久| 欧美激情精品久久久久久黑人| 国产精品一区二区久久国产| 国产偷国产偷亚洲清高网站| 亚洲国产天堂久久综合网| 欧美中文在线免费| 色黄久久久久久| 亚洲色图综合久久| 国产在线观看一区二区三区| 在线观看日韩专区| 法国裸体一区二区| 中文字幕亚洲综合久久| 美女视频黄免费的亚洲男人天堂| 国产香蕉精品视频一区二区三区|