從上一篇看出掏颊,簡單封裝后的deferred與如今的Promise非常相似某抓,尤其是最后那個(gè)返回dtd.promise()的例子揖膜,則直接返回了一個(gè)promise對象看锉。介紹了promise的前世以后姿锭,再來看看它的今生。
如今的promise伯铣,有異常捕獲呻此,可多個(gè)串聯(lián),Promise.all和Promise.race等用法腔寡。下面將根據(jù)promise的用法由淺入深的舉例子焚鲜。
首先,可以通過Promise將一個(gè)異步操作new成Promise的一個(gè)實(shí)例放前,從而我們在這個(gè)實(shí)例上進(jìn)行更加優(yōu)雅的操作忿磅,而不是之前的用callback形式,從前面的學(xué)習(xí)可以知道這樣做解耦了代碼凭语,很好體現(xiàn)了編程界 開放封閉 的原則葱她。這個(gè)例子見下圖,通過promise對加載圖片操作進(jìn)行封裝似扔。從而有對w的鏈?zhǔn)讲僮鞫中_@里有個(gè)小知識點(diǎn),想要第二個(gè).then操作接收到數(shù)據(jù)炒辉,從而處理數(shù)據(jù)豪墅,在第一個(gè).then操作后面要返回接收到的數(shù)數(shù)據(jù)(而這個(gè)數(shù)據(jù)針對這個(gè)例子是我們封裝操作的時(shí)候傳進(jìn)去的img信息)。
Promise構(gòu)造函數(shù)接受一個(gè)函數(shù)作為參數(shù)辆脸,該函數(shù)的參數(shù)分別是resolve和reject兩個(gè)函數(shù)但校,它們由JS引擎提供螃诅,不用我們部署啡氢。resolve函數(shù)的作用是,執(zhí)行resolve后术裸,將Promise對象狀態(tài)從'pending'變?yōu)?resolved'(.then中的第一個(gè)函數(shù)在監(jiān)聽到這個(gè)狀態(tài)變化倘是,則會執(zhí)行),同時(shí)可以傳遞參數(shù)出去;reject函數(shù)作用則是袭艺,執(zhí)行完它將Promise對象狀態(tài)從'pending'變?yōu)?rejected'(.then中的第二個(gè)函數(shù)在監(jiān)聽到這個(gè)狀態(tài)變化搀崭,則會執(zhí)行),也可以傳遞參數(shù)出去。所以說在封裝異步操作為Promise對象時(shí)候瘤睹,一定注意不要主動去觸發(fā)resolve或者reject升敲,否則你將得不到你想要的結(jié)果。比如下面的這個(gè)例子轰传,我們在封裝Promise對象的時(shí)候直接觸發(fā)了reject驴党,而不是在img.onerror時(shí)候才觸發(fā)它,并且這個(gè)例子里面?zhèn)魅胍粋€(gè)字符串获茬「圩可以看出,由于狀態(tài)發(fā)生變化恕曲,.then的第二個(gè)函數(shù)或者.catch監(jiān)聽到了則做出應(yīng)對鹏氧。
下面再接著舉一個(gè)封裝ajax的例子,方便與上面例子一些細(xì)節(jié)比較佩谣。(這里我覺得ajax在1.5之后已經(jīng)支持類似的鏈?zhǔn)讲僮靼鸦梗瑢?shí)際用的時(shí)候也不用封裝也能達(dá)到相同的效果(可以看我前面的一篇文章Deferred有舉例),但是為什么還有很多人去封裝成promise再用稿存,我也在思考笨篷?)
以前我們用ajax時(shí)候偶爾會遇到這樣的問題,當(dāng)我們需要將程序中的數(shù)據(jù)傳遞到callback函數(shù)里面瓣履,我們可能會采用下面的寫法:
現(xiàn)在有了promise我們可以做的更加優(yōu)雅率翅,因?yàn)閞esolve可以傳遞參數(shù),但是貌似規(guī)定只能傳一個(gè)參數(shù)袖迎,所以我們可以用數(shù)組或者對象形式冕臭,將我們要傳的多個(gè)參數(shù)進(jìn)行包裝,用數(shù)組傳遞例子如下:
實(shí)際工作中我們總要對promise實(shí)例進(jìn)行異常處理燕锥,在.這里我們用.catch捕獲異常辜贵,一般來說,我們不要在.then方法中定義rejected狀態(tài)的函數(shù)(then的第二個(gè)參數(shù))归形,而總是用catch方法托慨。這個(gè)寫法跟我們以前用的try{}catch{}的用法很相似。在《ECMAScript6入門》一書中學(xué)習(xí)到暇榴,catch的方法其實(shí)是指Promise.prototype.catch厚棵,它是.then(null,rejection)的別名,用于指定發(fā)生錯(cuò)誤時(shí)的回調(diào)函數(shù),但是請注意當(dāng)Promise狀態(tài)已經(jīng)變成resolved蔼紧,再拋出錯(cuò)誤是無效的婆硬,看下面的第二個(gè)圖片。
實(shí)際工作中奸例,我們經(jīng)常要控制異步操作的執(zhí)行順序彬犯,比如ajax的順序執(zhí)行,或者圖片的順序加載。比如實(shí)現(xiàn)圖片的順序加載的例子如下谐区,在第一個(gè)實(shí)例后返回第二個(gè)實(shí)例湖蜕。
? ?Promise.all接收一個(gè)promise數(shù)組,待全部完成之后宋列,統(tǒng)一執(zhí)行success重荠,比如下面的例子,打印出來的圖片寬度與上面一致虚茶,注意這里返回的是一個(gè)數(shù)組戈鲁,因?yàn)槭且唤Mpromise實(shí)例的返回。
Promise.race接受一個(gè)promise數(shù)組嘹叫,其中任何一個(gè)完成婆殿,就執(zhí)行success。