iOS Promise筆記(1)-概念及google/promises使用

本文使用的 Promises 是谷歌最近開(kāi)源的輕量贤徒,高性能昼弟,安全属瓣,測(cè)試完備的 Promise 框架员舵。https://github.com/google/promises

Swift 關(guān)于 Promise 的優(yōu)秀框架還有 PromiseKitBrightFutures

什么是Futures & Promises?

FuturePromise 其實(shí)是一個(gè)東西捉兴。很多iOS開(kāi)發(fā)者可能沒(méi)有聽(tīng)說(shuō)過(guò) Promise屯阀。Promise 在 JavaScript 中最為活躍。JavaScript 中大部分代碼都是單線程的轴术,在沒(méi)有引入 Promise 時(shí)难衰,開(kāi)發(fā)者一般編寫(xiě)回調(diào)函數(shù),但在某些特殊的情況下回調(diào)嵌套非常的多逗栽,代碼就會(huì)變得非常難讀盖袭,難以調(diào)試。在 iOS 中彼宠,Swift 閉包 closure 反復(fù)嵌套閉包(OC 代碼塊 block 嵌套代碼塊)的時(shí)候問(wèn)題也同樣嚴(yán)重鳄虱。通俗的說(shuō) Promise 就是鏈的方式對(duì)結(jié)果類型閉包的封裝,避免層層閉包重復(fù)嵌套難以閱讀凭峡。

簡(jiǎn)單場(chǎng)景

日常開(kāi)發(fā)中可能會(huì)使用這樣的網(wǎng)絡(luò)請(qǐng)求:

  • 第三方平臺(tái)授權(quán)獲取第三方 key
  • 使用 key 登錄獲取并保存 token
  • 使用 token 獲取用戶信息
facebookAuth() { result in
    switch result {
    case .success(let tokenString, let fbUserID):
        login(tokenString: tokenString, fbUserID: fbUserID) { result in
            switch result {
            case .success(let token):
                loadUserProfile(token: token) { result in
                    saveToken(token: token)
                    switch result {
                    case .success(let user):
                        saveUser(user: user)
                    case .failure(let error):
                        print("---LoadUserProfile--- Error: \(error)")
                    }
                }
            case .failure(let error):
                print("---Login--- Error: \(error)")
            }
        }
    case .failure(let error):
        print("---FBLogin--- Error: \(error)")
    }
}

可以看到即便是將請(qǐng)求方法剝離拙已,使用枚舉enum封裝了網(wǎng)絡(luò)請(qǐng)求回調(diào),代碼還是一層套一層摧冀,顯然是陷入了回調(diào)地獄倍踪。
在使用 Promise 后,代碼看起來(lái)像是這樣

facebookAuth()
 .then { tokenString, fbUserID in
    return login(tokenString: tokenString, fbUserID: fbUserID)
}.then { token in
    saveToken(token: token)
    return loadUserProfile(token: token)
}.then { user in
    saveUser(user: user)
}.catch { error in
    print("---Login Error---: \(error)")
}

上述就是一個(gè) Promise 如何為異步編程中回調(diào)地獄提供的幫助例子索昂,可讀性和可維護(hù)性都變得很高建车。

概念

Promise 是解決例如在多個(gè)線程中并行執(zhí)行重操作,延遲執(zhí)行代碼這些難以調(diào)試椒惨、容易中斷的問(wèn)題的解決方案之一缤至。

Promise 可以有三種狀態(tài):

pending   - 待定狀態(tài),Promise對(duì)象剛被初始化的狀態(tài)
fulfilled - 滿足狀態(tài)(成功情況康谆,可進(jìn)行例如更新UI操作)
rejected  - 拒絕狀態(tài)(拋出錯(cuò)誤)

一旦是 fulfilled 或 rejected 狀態(tài)领斥,Promise 不會(huì)再改變狀態(tài)

Promises 使用解析

Pending
let promise = Promise<String>.pending()
// ...
if success {
  promise.fulfill("Hello world")
} else {
  promise.reject(someError)
}

初始化 pending 狀態(tài)(暫時(shí)沒(méi)有異步操作),隨后根據(jù)狀態(tài)完成情況來(lái)更新 Promise 狀態(tài)沃暗。

Then
func work1(_ string: String) -> Promise<String> {
  return Promise {
    return string
  }
}

func work2(_ string: String) -> Promise<Int> {
  return Promise {
    return Int(string) ?? 0
  }
}

func work3(_ number: Int) -> Int {
  return number * number
}

work1("10").then { string in
  return work2(string)
}.then { number in
  return work3(number)
}.then { number in
  print(number)  // 100
}

用于鏈?zhǔn)竭B接函數(shù)組成的隊(duì)列月洛,回調(diào)鏈中的函數(shù)根據(jù)上一個(gè)函數(shù)狀態(tài)情況依次被調(diào)用。

Catch
work1("abc").then { string in
  return work2(string)
}.then { number in
  return work3(number)  // Never executed.
}.then { number in
  print(number)  // Never executed.
}.catch { error in
  print("Cannot convert string to number: \(error)")
}

拋出錯(cuò)誤描睦,只要出現(xiàn)異常膊存,忽略鏈中剩余的任何 then 塊导而,catch 可以防止在鏈中任何位置來(lái)處理錯(cuò)誤忱叭。

All
// Promises of same type:
all(contacts.map { MyClient.getAvatarFor(contact: $0) }).then(updateAvatars)

// Promises of different types:
all(
  MyClient.getLocationFor(contact: contact),
  MyClient.getAvatarFor(contact: contact)
).then { location, avatar in
  self.updateContact(location, avatar)
}

在一個(gè)塊中等待所有函數(shù)調(diào)用結(jié)束后更新?tīng)顟B(tài)隔崎。例如一個(gè)頁(yè)面的UI使用到三個(gè)網(wǎng)絡(luò)請(qǐng)求的數(shù)據(jù),等待全部加載完成再進(jìn)行刷新韵丑。

Always
getCurrentUserContactsAvatars().then { avatars in
  self.update(avatars)
}.catch { error in
  self.showErrorAlert(error)
}.always {
  self.label.text = "All done."
}

不論 promise 結(jié)果如何疙描,在這之后總是執(zhí)行某項(xiàng)任務(wù)堪唐。

Recover
getCurrentUserContactsAvatars().recover { error in
  print("Fallback to default avatars due to error: \(error)")
  return self.getDefaultsAvatars()
}.then { avatars in
  self.update(avatars)
}

可以默認(rèn)實(shí)現(xiàn)錯(cuò)誤處理,并且不打斷接下來(lái)鏈塊操作。

Resolve
func newAsyncMethodReturningAPromise() -> Promise<Data> {
  return resolve { handler in
    MyClient.wrappedAsyncMethodWithTypical(completion: handler)
  }
}

用于返回一個(gè)Promise丝蹭,提供一種常見(jiàn)的、方便的方法惨撇。

Timeout

超時(shí)處理

Validate
getAuthToken().validate { !$0.isEmpty }.then(getData).catch { error in
  print("Failed to get auth token: \(error))
}

validate 在不破壞鏈的情況下檢查返回結(jié)果虐秦,來(lái)判斷獲取的內(nèi)容是否可靠再進(jìn)行接下來(lái)的操作。

When
when(
  MyClient.getLocationFor(contact: contact),
  MyClient.getAvatarFor(contact: contact)
).then { location, avatar in
  if let location = location.value, let avatar = avatar.value {
    self.updateContact(location, avatar)
  } else {  // Optionally handle errors if needed.
    if let locationError = location.error {
      self.showErrorAlert(locationError)
    }
    if let avatarError = avatar.error {
      self.showErrorAlert(avatarError)
    }
  }
}

when 與 all 類似碗短,不同的是如果需要處理錯(cuò)誤細(xì)節(jié)受葛,使用when會(huì)顯得更加方便。

參考:
Under the hood of Futures & Promises in Swift
google/promises/index.md

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末偎谁,一起剝皮案震驚了整個(gè)濱河市总滩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌巡雨,老刑警劉巖闰渔,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異铐望,居然都是意外死亡冈涧,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門正蛙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)炕舵,“玉大人,你說(shuō)我怎么就攤上這事跟畅⊙式睿” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵徊件,是天一觀的道長(zhǎng)奸攻。 經(jīng)常有香客問(wèn)我,道長(zhǎng)虱痕,這世上最難降的妖魔是什么睹耐? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮部翘,結(jié)果婚禮上硝训,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好窖梁,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布赘风。 她就那樣靜靜地躺著,像睡著了一般纵刘。 火紅的嫁衣襯著肌膚如雪邀窃。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,046評(píng)論 1 285
  • 那天假哎,我揣著相機(jī)與錄音瞬捕,去河邊找鬼。 笑死舵抹,一個(gè)胖子當(dāng)著我的面吹牛肪虎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播惧蛹,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼笋轨,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了赊淑?” 一聲冷哼從身側(cè)響起爵政,我...
    開(kāi)封第一講書(shū)人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎陶缺,沒(méi)想到半個(gè)月后钾挟,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡饱岸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年掺出,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片苫费。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡汤锨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出百框,到底是詐尸還是另有隱情闲礼,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布铐维,位于F島的核電站柬泽,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏嫁蛇。R本人自食惡果不足惜锨并,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望睬棚。 院中可真熱鬧第煮,春花似錦解幼、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至揽趾,卻和暖如春台汇,著一層夾襖步出監(jiān)牢的瞬間苛骨,已是汗流浹背篱瞎。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留痒芝,地道東北人俐筋。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像严衬,于是被迫代替她去往敵國(guó)和親澄者。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 你不知道JS:異步 第三章:Promises 在第二章请琳,我們指出了采用回調(diào)來(lái)表達(dá)異步和管理并發(fā)時(shí)的兩種主要不足:缺...
    purple_force閱讀 2,052評(píng)論 0 4
  • 特別說(shuō)明粱挡,為便于查閱,文章轉(zhuǎn)自https://github.com/getify/You-Dont-Know-JS...
    殺破狼real閱讀 871評(píng)論 0 2
  • Promise 對(duì)象 Promise 的含義 Promise 是異步編程的一種解決方案俄精,比傳統(tǒng)的解決方案——回調(diào)函...
    neromous閱讀 8,698評(píng)論 1 56
  • Promiese 簡(jiǎn)單說(shuō)就是一個(gè)容器询筏,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果,語(yǔ)法上說(shuō)竖慧,Pr...
    雨飛飛雨閱讀 3,348評(píng)論 0 19
  • 本文適用的讀者 本文寫(xiě)給有一定Promise使用經(jīng)驗(yàn)的人嫌套,如果你還沒(méi)有使用過(guò)Promise,這篇文章可能不適合你圾旨,...
    HZ充電大喵閱讀 7,296評(píng)論 6 19