使用Promise鏈?zhǔn)秸{(diào)用解決多個(gè)異步回調(diào)的問(wèn)題
介紹
所謂Promise,簡(jiǎn)單來(lái)說(shuō)就是一個(gè)容器,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果。
缺少場(chǎng)景支撐,對(duì)于新手而言,很難理解Promise的意義。
在《你不知道的JavaScript中》有個(gè)場(chǎng)景介紹得很形象:
我走到快餐店的柜臺(tái),點(diǎn)了一個(gè)芝士漢堡。我交給收銀員1.47美元。通過(guò)下訂單并付款,我已經(jīng)發(fā)出了一個(gè)對(duì)某個(gè)值(就是那個(gè)漢堡)的請(qǐng)求。我已經(jīng)啟 動(dòng)了一次交易。
但是,通常我不能馬上就得到這個(gè)漢堡。收銀員會(huì)交給我某個(gè)東西來(lái)代替漢堡:一張帶有 訂單號(hào)的收據(jù)。訂單號(hào)就是一個(gè) IOU(I owe you, 我欠你的)承諾(promise),保證了最 終我會(huì)得到我的漢堡。
所以我得好好保留我的收據(jù)和訂單號(hào)。我知道這代表了我未來(lái)的漢堡,所以不需要擔(dān)心, 只是現(xiàn)在我還是很餓!
在等待的過(guò)程中,我可以做點(diǎn)其他的事情,比如給朋友發(fā)個(gè)短信:“嗨,要來(lái)和我一起吃 午飯嗎?我正要吃芝士漢堡?!?br />
我已經(jīng)在想著未來(lái)的芝士漢堡了, 盡管現(xiàn)在我還沒(méi)有拿到手。 我的大腦之所以可以這么 做,是因?yàn)樗呀?jīng)把訂單號(hào)當(dāng)作芝士漢堡的占位符了。從本質(zhì)上講,這個(gè)占位符使得這個(gè) 值不再依賴(lài)時(shí)間。這是一個(gè)未來(lái)值。
終于, 我聽(tīng)到服務(wù)員在喊“訂單 113” , 然后愉快地拿著收據(jù)走到柜臺(tái), 把收據(jù)交給收銀 員,換來(lái)了我的芝士漢堡。
換句話說(shuō), 一旦我需要的值準(zhǔn)備好了, 我就用我的承諾值(value-promise)換取這個(gè)值 本身。
但是,還可能有另一種結(jié)果。他們叫到了我的訂單號(hào),但當(dāng)我過(guò)去拿芝士漢堡的時(shí)候,收 銀員滿是歉意地告訴我:“不好意思,芝士漢堡賣(mài)完了?!背俗鳛轭櫩蛯?duì)這種情況感到憤 怒之外,我們還可以看到未來(lái)值的一個(gè)重要特性:它可能成功,也可能失敗。
每次點(diǎn)芝士漢堡,我都知道最終要么得到一個(gè)芝士漢堡,要么得到一個(gè)漢堡包售罄的壞消息,那我就得找點(diǎn)別的當(dāng)午飯了。
所以Promise的出現(xiàn)其實(shí)是作為異步編程的一種解決方案。比傳統(tǒng)的解決方案-回調(diào)函數(shù)和事件-更加合理、強(qiáng)大。
Promise的基本用法
var p1 = new Promise((resolve, reject) => { setTimeout(resolve, 1000, 'done'); }) p1.then(data=>{ console.log(data); // done })
Promise一個(gè)明顯的好處便是可以用來(lái)解決回調(diào)地獄。特別是在處理多個(gè)回調(diào)相互依賴(lài)的情況。
使用Promise解決多個(gè)異步依賴(lài)調(diào)用
Promise提供了一個(gè)方法Promise.all([p1,p2,p3])
,用于將多個(gè)Promise實(shí)例,包裝成一個(gè)新的Promise實(shí)例。接收的參數(shù)是一個(gè)數(shù)組,p1、p2、p3都是Promise對(duì)象。
此時(shí)Promise.all的狀態(tài)取決于它的參數(shù)。
分兩種情況:
- p1、p2、p3的狀態(tài)都是resolve的時(shí)候,
Promise.all
的狀態(tài)才會(huì)變成resolve; - 只要p1、p2、p3中有一個(gè)的狀態(tài)為reject,那么
Promise.all
的狀態(tài)就會(huì)變成reject;
所以我們可以用Promise.all()
來(lái)解決多個(gè)異步依賴(lài)調(diào)用。
比如我們平常經(jīng)常遇到的一種情況:
網(wǎng)站中需要先獲取用戶名,然后再根據(jù)用戶名去獲取用戶信息。這里獲取用戶名getUserName()
和獲取用戶信息getUser()
都是調(diào)用接口的異步請(qǐng)求。在獲取用戶信息之前,需要先獲得用戶名。也就是說(shuō)getUser依賴(lài)于getUserName的狀態(tài)。所以我們可以將這兩個(gè)請(qǐng)求通過(guò)Promise.all()
封裝成一個(gè)新的Promise對(duì)象。
function getUserPromise(promiseX, promiseY){ return Promise.all([promiseX, promiseY]) .then(values => // 返回的values由 promiseX 與 promiseY返回的值所構(gòu)成的數(shù)組。 values ) } function getUserName(){ let data = 'superman'; return new Promise((resolve, reject) => { setTimeout(resolve(data), 1000); }) } function getUser(){ let data = { id:1, username: 'superman', gender: 'male' } return new Promise((resolve, reject) => { setTimeout(resolve(data), 2000); }) } getUserPromise(getUserName(), getUser()) .then(data => { // 這里的data就是包含了getUserName 和 getUser返回值所組成的數(shù)組 console.log(data); // [ 'superman', { id: 1, username: 'superman', gender: 'male' } ] })
使用Promise的鏈?zhǔn)秸{(diào)用
function getUserName(){ let data = 'superman'; return new Promise((resolve, reject) => { setTimeout(resolve(data), 4000); }) } function getUser(username){ let data = { id:1, username: 'superman', gender: 'male' } return new Promise((resolve, reject) => { if(username){ setTimeout(resolve(data), 2000); } else{ reject('err'); } }) } getUserName().then(username => { return getUser(); }) .then(user => { console.log(user); }) .catch(err => { console.log(err); })
有了Promise的鏈?zhǔn)秸{(diào)用,再也不同擔(dān)心回調(diào)地獄的問(wèn)題了。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流。
相關(guān)文章
實(shí)例分析瀏覽器中“JavaScript解析器”的工作原理
本文主要對(duì)javascript解析器的工作原理進(jìn)行實(shí)例分析,具有很好的參考價(jià)值,下面就跟小編一起來(lái)看下吧2016-12-12JavaScript中定時(shí)控制Throttle、Debounce和Immediate詳解
大家可能都知道JavaScript遵循事件驅(qū)動(dòng)的編程范例,這意味著一些行為可以激活一些響應(yīng),并且這些響應(yīng)僅在發(fā)生特定的行為時(shí)才被激活。這篇文章將給大家詳細(xì)介紹JavaScript中的定時(shí)控制Throttle、Debounce和Immediate,有需要的朋友們可以參考借鑒,下面來(lái)一起看看吧。2016-11-11JavaScript獲取頁(yè)面上某個(gè)元素的代碼
大多數(shù)的javascript操作都需要獲取先獲取頁(yè)面上的某個(gè)元素,引用其為當(dāng)前腳本中的一個(gè)對(duì)象,然后加以操作或獲取節(jié)點(diǎn)樹(shù)形。2011-03-03js漢字排序問(wèn)題 支持中英文混排,兼容各瀏覽器,包括CHROME
這套排序機(jī)制同時(shí)兼容了IE和ff 可以實(shí)現(xiàn)所有瀏覽器下排序的統(tǒng)一哦2011-12-12bootstrap學(xué)習(xí)筆記之初識(shí)bootstrap
Bootstrap是一款目前非常流行的前端框架,簡(jiǎn)單的說(shuō),就是html,css,javascript的工具集。本文給大家介紹bootstrap學(xué)習(xí)筆記之初識(shí)bootstrap,感興趣的朋友一起學(xué)習(xí)吧2016-06-06js實(shí)現(xiàn)HTML中Select二級(jí)聯(lián)動(dòng)的實(shí)例
下面小編就為大家分享一篇js實(shí)現(xiàn)HTML中Select二級(jí)聯(lián)動(dòng)的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-01-01js實(shí)現(xiàn)按鈕控制圖片360度翻轉(zhuǎn)特效的方法
這篇文章主要介紹了js實(shí)現(xiàn)按鈕控制圖片360度翻轉(zhuǎn)特效的方法,涉及HTML5中canvas方法的使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-02-02微信小程序?qū)崿F(xiàn)鼠標(biāo)拖動(dòng)效果示例
這篇文章主要介紹了微信小程序?qū)崿F(xiàn)鼠標(biāo)拖動(dòng)效果,涉及微信小程序事件綁定及元素屬性動(dòng)態(tài)操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-12-12