Javascript中的異步編程規(guī)范Promises/A詳細(xì)介紹
Javascript里異步編程逐漸被大家接受,先前大家一般通過(guò)回調(diào)嵌套,setTimeout、setInterval等方式實(shí)現(xiàn),代碼看起來(lái)非常不直觀,不看整個(gè)代碼邏輯很難快速理解。Javascript里異步函數(shù)大概有I/O函數(shù)(Ajax、postMessage、img load、script load等)、計(jì)時(shí)函數(shù)(setTimeout、setInterval)等。
這些我們都很熟悉,在復(fù)雜的應(yīng)用中往往會(huì)嵌套多層,甚至以為某些步驟未完成而導(dǎo)致程序異常,最簡(jiǎn)單的例子:比如你往DOM中注入節(jié)點(diǎn),你必須等待節(jié)點(diǎn)注入后在操作這個(gè)節(jié)點(diǎn),當(dāng)大量節(jié)點(diǎn)注入的時(shí)候,時(shí)間往往很難把握。如果我們得代碼依賴第三方api的數(shù)據(jù)。我們無(wú)法獲悉一個(gè)API響應(yīng)的延遲時(shí)間,應(yīng)用程序的其他部分可能會(huì)被阻塞,直到它返回結(jié)果。Promises對(duì)這個(gè)問(wèn)題提供了一個(gè)更好的解決方案,它是非阻塞的,并且與代碼完全解耦 。
那么,我看看Javascript里異步編程,首先推薦大家看看相對(duì)來(lái)說(shuō)比較流行的Promises/A規(guī)范。
Promises/A規(guī)范
注:為了便于理解,描述可能和Promises/A規(guī)范有所出入;
CommonJS之Promises/A規(guī)范,通過(guò)規(guī)范API接口來(lái)簡(jiǎn)化異步編程,使我們的異步邏輯代碼更易理解。
遵循Promises/A規(guī)范的實(shí)現(xiàn)我們稱之為Promise對(duì)象,Promise對(duì)象有且僅有三種狀態(tài):unfulfilled(未完成)、fulfilled(已完成)、failed(失敗/拒絕);初始創(chuàng)建的時(shí)候是unfulfilled(未完成)狀態(tài),狀態(tài)只可以從unfulfilled(未完成)變成fulfilled(已完成),或者unfulfilled(未完成)變成failed(失敗/拒絕)。狀態(tài)一旦變成fulfilled(已完成)或者failed(失敗/拒絕),狀態(tài)就不能再變了。
Promises/A規(guī)范提供了一個(gè)在程序中描述延時(shí)(或?qū)?lái))概念的解決方案。主要的思想不是執(zhí)行一個(gè)方法然后阻塞應(yīng)用程序等待結(jié)果返回后再回調(diào)其他方法,而是返回一個(gè)Promise對(duì)象來(lái)滿足未來(lái)監(jiān)聽(tīng)。fulfilled狀態(tài)和failed狀態(tài)都可以被監(jiān)聽(tīng)。Promise通過(guò)實(shí)現(xiàn)一個(gè)then接口來(lái)返回Promise對(duì)象來(lái)注冊(cè)回調(diào):
then接口用于監(jiān)聽(tīng)一個(gè)Promise的不同狀態(tài)。fulfilledHandler用于監(jiān)聽(tīng)fulfilled(已完成)狀態(tài),errorHandler用于監(jiān)聽(tīng)failed(失敗/拒絕)狀態(tài),progressHandler用于監(jiān)聽(tīng)unfulfilled(未完成)狀態(tài)。Promise不強(qiáng)制實(shí)現(xiàn)unfulfilled(未完成)的事件監(jiān)聽(tīng)(例如我們知道舊版本的jQuery(1.5,1.6)的Deferred就是一個(gè)Promise的實(shí)現(xiàn),但沒(méi)有實(shí)現(xiàn)對(duì)unfulfilled(未完成)狀態(tài)的監(jiān)聽(tīng)來(lái)回調(diào)progressHandler)。
一般認(rèn)為,then接口返回的是一個(gè)新的Promise對(duì)象,而不是原來(lái)的Promise對(duì)象,這個(gè)新的新的Promise對(duì)象可以理解為是原來(lái)Promise對(duì)象的一個(gè)視圖,它只包含原有Promise對(duì)象的一組方法,這些方法只能觀察原有Promise對(duì)象的狀態(tài),而無(wú)法更改deferred對(duì)象的內(nèi)在狀態(tài)。這樣可以避免多個(gè)調(diào)用者之間的沖突,多個(gè)調(diào)用者可以通過(guò)改變新的Promise對(duì)象狀態(tài)而不影響別的調(diào)用者。
另外,Promise提供了resolve(實(shí)現(xiàn)狀態(tài)由未完成到已完成)和reject(實(shí)現(xiàn)狀態(tài)由未完成到拒絕或失?。﹥蓚€(gè)接口實(shí)現(xiàn)狀態(tài)的轉(zhuǎn)變。
發(fā)一張圖片幫助理解一下:

有了Promise,就可以以同步的思維去編寫(xiě)異步的邏輯了。在異步函數(shù)里,不能使用try/catch捕獲異常,也不能拋出異常。有了Promise,我們可以直接顯式定義errorHandler,相當(dāng)于捕獲異常。
以下是幾個(gè)遵循Promises/A規(guī)范的類庫(kù),when,q,rsvp.js,jQuery.Deferred等等。
相關(guān)文章
jquery實(shí)現(xiàn)點(diǎn)擊其他區(qū)域時(shí)隱藏下拉div和遮罩層的方法
這篇文章主要介紹了jquery實(shí)現(xiàn)點(diǎn)擊其他區(qū)域時(shí)隱藏下拉div和遮罩層的方法,涉及jQuery響應(yīng)鼠標(biāo)事件動(dòng)態(tài)改變頁(yè)面元素樣式的功能,需要的朋友可以參考下2015-12-12
在jquery中的ajax方法怎樣通過(guò)JSONP進(jìn)行遠(yuǎn)程調(diào)用
這一節(jié)主要演示下在JQUERY中的ajax方法怎樣通過(guò)JSONP進(jìn)行遠(yuǎn)程調(diào)用,需要的朋友可以參考下2014-04-04
jQuery復(fù)合事件結(jié)合toggle()方法的用法示例
這篇文章主要介紹了jQuery復(fù)合事件結(jié)合toggle()方法的用法,實(shí)例分析了toggle()方法的功能、定義以及與復(fù)合事件結(jié)合使用的操作技巧,需要的朋友可以參考下2017-06-06
詳解jQuery移動(dòng)頁(yè)面開(kāi)發(fā)中的ui-grid網(wǎng)格布局使用
這篇文章主要介紹了jQuery移動(dòng)頁(yè)面開(kāi)發(fā)中的ui-grid網(wǎng)格布局使用,以講解多列頁(yè)面布局方式為主,需要的朋友可以參考下2015-12-12
jQuery插件formValidator實(shí)現(xiàn)表單驗(yàn)證
這篇文章主要為大家詳細(xì)介紹了jQuery插件formValidator實(shí)現(xiàn)表單驗(yàn)證的相關(guān)資料,需要的朋友可以參考下2016-05-05
jquery實(shí)現(xiàn)界面點(diǎn)擊按鈕彈出懸浮框
這篇文章主要為大家詳細(xì)介紹了jquery實(shí)現(xiàn)界面點(diǎn)擊按鈕彈出懸浮框,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
ASP.NET jQuery 實(shí)例13 原創(chuàng)jQuery文本框字符限制插件-TextArea Counter
這節(jié)介紹一個(gè)自己寫(xiě)的jQuery文本框字符限制插件,至于如何寫(xiě)插件,我這里就不多講了,可以查看相關(guān)介紹,這里主要介紹下該插件的功能2012-02-02
jQuery Tags Input Plugin(添加/刪除標(biāo)簽插件)詳解
本文主要介紹jQuery Tags Input Plugin添加/刪除標(biāo)簽插件的用法,非常實(shí)用,有需要的朋友可以參考一下。2016-06-06
JQuery+CSS實(shí)現(xiàn)圖片上放置按鈕的方法
這篇文章主要介紹了JQuery+CSS實(shí)現(xiàn)圖片上放置按鈕的方法,涉及jQuery鼠標(biāo)事件及頁(yè)面樣式的相關(guān)技巧,需要的朋友可以參考下2015-05-05
jquery+css+html實(shí)現(xiàn)飛機(jī)大戰(zhàn)游戲
這篇文章主要為大家詳細(xì)介紹了jquery+css+html實(shí)現(xiàn)飛機(jī)大戰(zhàn)游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05

