偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

一文帶你使用 Swift 實(shí)現(xiàn) Promise

開發(fā) 前端
我最近在找如何使用 Swift 實(shí)現(xiàn) Promise 的資料,因?yàn)闆]找到好的文章,所以我想自己寫一篇。通過本文,我們將實(shí)現(xiàn)自己的 Promise 類型,以便明了其背后的邏輯。

[[421175]]

前言

我最近在找如何使用 Swift 實(shí)現(xiàn) Promise 的資料,因?yàn)闆]找到好的文章,所以我想自己寫一篇。通過本文,我們將實(shí)現(xiàn)自己的 Promise 類型,以便明了其背后的邏輯。

要注意這個實(shí)現(xiàn)完全不適合生產(chǎn)環(huán)境。例如,我們的 Promise 沒有提供任何錯誤機(jī)制,也沒有覆蓋線程相關(guān)的場景。我會在文章的后面提供一些有用的資源以及完整實(shí)現(xiàn)的鏈接,以饗愿深入挖掘的讀者。

注:為了讓本教程更有趣一點(diǎn),我選擇使用 TDD 來進(jìn)行介紹。我們會先寫測試,然后確保它們一個個通過。

第一個測試

先寫第一個測試:

  1. test(named: "0. Executor function is called immediately") { assert, done in 
  2.     var string: String = "" 
  3.     _ = Promise { string = "foo" } 
  4.     assert(string == "foo"
  5.     done() 

通過此測試,我們想實(shí)現(xiàn):傳遞一個函數(shù)給 Promise 的初始化函數(shù),并立即調(diào)用此函數(shù)。

注:我們沒有使用任何測試框架,僅僅使用一個自定義的test方法,它在 Playground 中模擬斷言(gist[1])。

當(dāng)我們運(yùn)行 Playground,編譯器會報錯:

  1. error: Promise.playground:41:9: error: use of unresolved identifier 'Promise' 
  2.     _ = Promise { string = "foo" } 
  3.         ^~~~~~~ 

合理,我們需要定義 Promise 類。

  1. class Promise { 
  2.  

再運(yùn)行,錯誤變?yōu)椋?/p>

  1. error: Promise.playground:44:17: error: argument passed to call that takes no arguments 
  2.     _ = Promise { string = "foo" } 
  3.                 ^~~~~~~~~~~~~~~~~~ 

我們必須定義一個初始化函數(shù),它接受一個閉包作為參數(shù)。而且這個閉包應(yīng)該被立即調(diào)用。

  1. class Promise { 
  2.  
  3.     init(executor: () -> Void) { 
  4.         executor() 
  5.     } 

由此,我們通過第一個測試。目前我們還沒有寫出什么值得夸耀的東西,但耐心一點(diǎn),我們的實(shí)現(xiàn)將在下一節(jié)繼續(xù)增長。

  1. • Test 0. Executor function is called immediately passed  

我們先將此測試注釋掉,因?yàn)閷淼?Promise 實(shí)現(xiàn)會變得有些不同。

最低限度

第二個測試如下:

  1. test(named: "1.1 Resolution handler is called when promise is resolved sync") { assert, done in 
  2.     let string: String = "foo" 
  3.     let promise = Promise<String> { resolve in 
  4.         resolve(string) 
  5.     } 
  6.     promise.then { (value: String) in 
  7.         assert(string == value) 
  8.         done() 
  9.     } 

這個測試挺簡單,但我們添加了一些新內(nèi)容到 Promise 類。我們創(chuàng)建的這個 promise 有一個 resolution handler(即閉包的resolve參數(shù)),之后立即調(diào)用它(傳遞一個 value)。然后,我們使用 promise 的 then 方法來訪問 value 并用斷言確保其值。

在開始實(shí)現(xiàn)之前,我們需要引入另外一個不太一樣的測試。

  1. test(named: "1.2 Resolution handler is called when promise is resolved async") { assert, done in 
  2.     let string: String = "foo" 
  3.     let promise = Promise<String> { resolve in 
  4.         after(0.1) { 
  5.             resolve(string) 
  6.         } 
  7.     } 
  8.     promise.then { (value: String) in 
  9.         assert(string == value) 
  10.         done() 
  11.     } 

不同于測試 1.1,這里的resove方法被延遲調(diào)用。這意味著,在then里,value 不會立馬可用(因?yàn)?0.1 秒的延遲,調(diào)用then時,resolve還未被調(diào)用)。

我們開始理解這里的“問題”。我們必須處理異步。

我們的 promise 是一個狀態(tài)機(jī)。當(dāng)它被創(chuàng)建時,promise 處于pending狀態(tài)。一旦resolve方法被調(diào)用(與一個 value),我們的 promise 將轉(zhuǎn)到resolved狀態(tài),并存儲這個 value。

then方法可在任意時刻被調(diào)用,而不管 promise 的內(nèi)部狀態(tài)(即不管 promise 是否已有一個 value)。當(dāng)這個 promise 處于pending狀態(tài)時,我們調(diào)用then,value 將不可用,因此,我們需要存儲此回調(diào)。之后一旦 promise 變成resolved,我們就能使用 resolved value 來觸發(fā)同樣的回調(diào)。

現(xiàn)在我們對要實(shí)現(xiàn)的東西有了更好的理解,那就先以修復(fù)編譯器的報錯開始。

  1. error: Promise.playground:54:19: error: cannot specialize non-generic type 'Promise' 
  2.     let promise = Promise<String> { resolve in 
  3.                   ^      ~~~~~~~~ 

我們必須給Promise類型添加泛型。誠然,一個 promise 是這樣的東西:它關(guān)聯(lián)著一個預(yù)定義的類型,并能在被解決時,將一個此類型的 value 保留住。

  1. class Promise<Value> { 
  2.  
  3.     init(executor: () -> Void) { 
  4.         executor() 
  5.     } 

現(xiàn)在錯誤為:

  1. error: Promise.playground:54:37: error: contextual closure type '() -> Void' expects 0 arguments, but 1 was used in closure body 
  2.     let promise = Promise<String> { resolve in 
  3.                                     ^ 

我們必須提供一個resolve函數(shù)傳遞給初始化函數(shù)(即 executor)。

  1. class Promise<Value> { 
  2.  
  3.     init(executor: (_ resolve: (Value) -> Void) -> Void) { 
  4.         executor() 
  5.     } 

注意這個 resolve 參數(shù)是一個函數(shù),它消耗一個 value:(Value) -> Void。一旦 value 被確定,這個函數(shù)將被外部世界調(diào)用。

編譯器依然不開心,因?yàn)槲覀冃枰峁┮粋€resolve函數(shù)給executor。讓我們創(chuàng)建一個private的吧。

  1. class Promise<Value> { 
  2.  
  3.     init(executor: (_ resolve: @escaping (Value) -> Void) -> Void) { 
  4.         executor(resolve) 
  5.     } 
  6.  
  7.     private func resolve(_ value: Value) -> Void { 
  8.         // To implement 
  9.         // This will be called by the outside world when a value is determined 
  10.     } 

我們將在稍后實(shí)現(xiàn)resolve,當(dāng)所有錯誤都被解決時。

下一個錯誤很簡單,方法then還未定義。

  1. error: Promise.playground:61:5: error: value of type 'Promise<String>' has no member 'then' 
  2.     promise.then { (value: String) in 
  3.     ^~~~~~~ ~~~~ 

讓我們修復(fù)之。

  1. class Promise<Value> { 
  2.  
  3.     init(executor: (_ resolve: @escaping (Value) -> Void) -> Void) { 
  4.         executor(resolve) 
  5.     } 
  6.  
  7.     func then(onResolved: @escaping (Value) -> Void) { 
  8.         // To implement 
  9.     } 
  10.  
  11.     private func resolve(_ value: Value) -> Void { 
  12.         // To implement 
  13.     } 

現(xiàn)在編譯器開心了,讓我們回到開始的地方。

我們之前說過一個Promise就是一個狀態(tài)機(jī),它有一個pending狀態(tài)和一個resolved狀態(tài)。我們可以使用 enum 來定義它們。

  1. enum State<T> { 
  2.     case pending 
  3.     case resolved(T) 

Swift 的美妙讓我們可以直接存儲 promise 的 value 在 enum 中。

現(xiàn)在我們需要在Promise的實(shí)現(xiàn)中定義一個狀態(tài),其默認(rèn)值為.pending。我們還需要一個私有函數(shù),它能在當(dāng)前還處于.pending狀態(tài)時更新狀態(tài)。

  1. class Promise<Value> { 
  2.  
  3.     enum State<T> { 
  4.         case pending 
  5.         case resolved(T) 
  6.     } 
  7.  
  8.     private var state: State<Value> = .pending 
  9.  
  10.     init(executor: (_ resolve: @escaping (Value) -> Void) -> Void) { 
  11.         executor(resolve) 
  12.     } 
  13.  
  14.     func then(onResolved: @escaping (Value) -> Void) { 
  15.         // To implement 
  16.     } 
  17.  
  18.     private func resolve(_ value: Value) -> Void { 
  19.         // To implement 
  20.     } 
  21.  
  22.     private func updateState(to newState: State<Value>) { 
  23.         guard case .pending = state else { return } 
  24.         state = newState 
  25.     } 

注意updateState(to:)函數(shù)先檢查了當(dāng)前處于.pending狀態(tài)。如果 promise 已經(jīng)處于.resolved狀態(tài),那它就不能再變成其他狀態(tài)了。

現(xiàn)在是時候在必要時更新 promise 的狀態(tài),即,當(dāng)resolve函數(shù)被外部世界傳遞 value 調(diào)用時。

  1. private func resolve(_ value: Value) -> Void { 
  2.     updateState(to: .resolved(value)) 

快好了,只缺少 then 方法還未實(shí)現(xiàn)。我們說過必須存儲回調(diào),并在 promise 被解決時調(diào)用回調(diào)。這就來實(shí)現(xiàn)之。

  1. class Promise<Value> { 
  2.  
  3.     enum State<T> { 
  4.         case pending 
  5.         case resolved(T) 
  6.     } 
  7.  
  8.     private var state: State<Value> = .pending 
  9.     // we store the callback as an instance variable 
  10.     private var callback: ((Value) -> Void)? 
  11.  
  12.     init(executor: (_ resolve: @escaping (Value) -> Void) -> Void) { 
  13.         executor(resolve) 
  14.     } 
  15.  
  16.     func then(onResolved: @escaping (Value) -> Void) { 
  17.         // store the callback in all cases 
  18.         callback = onResolved 
  19.         // and trigger it if needed 
  20.         triggerCallbackIfResolved() 
  21.     } 
  22.  
  23.     private func resolve(_ value: Value) -> Void { 
  24.         updateState(to: .resolved(value)) 
  25.     } 
  26.  
  27.     private func updateState(to newState: State<Value>) { 
  28.         guard case .pending = state else { return } 
  29.         state = newState 
  30.         triggerCallbackIfResolved() 
  31.     } 
  32.  
  33.     private func triggerCallbackIfResolved() { 
  34.         // the callback can be triggered only if we have a value, 
  35.         // meaning the promise is resolved 
  36.         guard case let .resolved(value) = state else { return } 
  37.         callback?(value) 
  38.         callback = nil 
  39.     } 

我們定義了一個實(shí)例變量callback,以在 promise 處于.pending狀態(tài)時保留回調(diào)。同時我們創(chuàng)建一個方法triggerCallbackIfResolved,它先檢查狀態(tài)是否為.resolved,然后傳遞拆包的 value 給回調(diào)。這個方法在兩個地方被調(diào)用。一個是then方法中,如果 promise 已經(jīng)在調(diào)用then時被解決。另一個在updateState方法中,因?yàn)槟鞘?promise 更新其內(nèi)部狀態(tài)從.pending到.resolved的地方。

有了這些修改,我們的測試就成功通過了。

  1. • Test 1.1 Resolution handler is called when promise is resolved sync passed (1 assertions) 
  2. • Test 1.2 Resolution handler is called when promise is resolved async passed (1 assertions) 

我們走對了路,但我們還需要做出一點(diǎn)改變,以得到一個真正的Promise實(shí)現(xiàn)。先來看看測試。

  1. test(named: "2.1 Promise supports many resolution handlers sync") { assert, done in 
  2.     let string: String = "foo" 
  3.     let promise = Promise<String> { resolve in 
  4.         resolve(string) 
  5.     } 
  6.     promise.then { value in 
  7.         assert(string == value) 
  8.     } 
  9.     promise.then { value in 
  10.         assert(string == value) 
  11.         done() 
  12.     } 
  1. test(named: "2.2 Promise supports many resolution handlers async") { assert, done in 
  2.     let string: String = "foo" 
  3.     let promise = Promise<String> { resolve in 
  4.         after(0.1) { 
  5.             resolve(string) 
  6.         } 
  7.     } 
  8.     promise.then { value in 
  9.         assert(string == value) 
  10.     } 
  11.     promise.then { value in 
  12.         assert(string == value) 
  13.         done() 
  14.     } 

這回我們對每個 promise 都調(diào)用了兩次then。

先看看測試輸出。

  1. • Test 2.1 Promise supports many resolution handlers sync passed (2 assertions) 
  2. • Test 2.2 Promise supports many resolution handlers async passed (1 assertions) 

雖然測試通過了,但你可能也注意問題。測試 2.2 只有一個斷言,但應(yīng)該是兩個。

如果我們思考一下,這其實(shí)符合邏輯。誠然,在異步的測試 2.2 中,當(dāng)?shù)谝粋€then被調(diào)用時,promise 還處于.pending狀態(tài)。如我們之前所見,我們存儲了第一次then的回調(diào)。但當(dāng)我們第二次調(diào)用then時,promise 還是沒有被解決,依然處于.pending狀態(tài),于是,我們將回調(diào)擦除換成了新的。只有第二個回調(diào)會在將來被執(zhí)行,第一個被忘記了。這使得測試雖然通過,但只有一個斷言而不是兩個。

解決辦法也很簡單,就是存儲一個回調(diào)的數(shù)組,并在promise被解決時觸發(fā)它們。

讓我們更新一下。

  1. class Promise<Value> { 
  2.  
  3.     enum State<T> { 
  4.         case pending 
  5.         case resolved(T) 
  6.     } 
  7.  
  8.     private var state: State<Value> = .pending 
  9.     // We now store an array instead of a single function 
  10.     private var callbacks: [(Value) -> Void] = [] 
  11.  
  12.     init(executor: (_ resolve: @escaping (Value) -> Void) -> Void) { 
  13.         executor(resolve) 
  14.     } 
  15.  
  16.     func then(onResolved: @escaping (Value) -> Void) { 
  17.         callbacks.append(onResolved) 
  18.         triggerCallbacksIfResolved() 
  19.     } 
  20.  
  21.     private func resolve(_ value: Value) -> Void { 
  22.         updateState(to: .resolved(value)) 
  23.     } 
  24.  
  25.     private func updateState(to newState: State<Value>) { 
  26.         guard case .pending = state else { return } 
  27.         state = newState 
  28.         triggerCallbacksIfResolved() 
  29.     } 
  30.  
  31.     private func triggerCallbacksIfResolved() { 
  32.         guard case let .resolved(value) = state else { return } 
  33.         // We trigger all the callbacks 
  34.         callbacks.forEach { callback in callback(value) } 
  35.         callbacks.removeAll() 
  36.     } 

測試通過,而且都有兩個斷言。

  1. • Test 2.1 Promise supports many resolution handlers sync passed (2 assertions) 
  2. • Test 2.2 Promise supports many resolution handlers async passed (2 assertions) 

恭喜!我們已經(jīng)創(chuàng)建了自己的Promise類。你已經(jīng)可以使用它來抽象異步邏輯,但它還有限制。

注:如果從全局來看,我們知道then可以被重命名為observe。它的目的是消費(fèi) promise 被解決后的 value,但它不返回什么。這意味著我們暫時沒法串聯(lián)多個 promise。

串聯(lián)多個 Promise

如果我們不能串聯(lián)多個 promise,那我們的Promise實(shí)現(xiàn)就不算完整。

先來看看測試,它將幫助我們實(shí)現(xiàn)這個特性。

  1. test(named: "3. Resolution handlers can be chained") { assert, done in 
  2.     let string: String = "foo" 
  3.     let promise = Promise<String> { resolve in 
  4.         after(0.1) { 
  5.             resolve(string) 
  6.         } 
  7.     } 
  8.     promise 
  9.         .then { value in 
  10.             return Promise<String> { resolve in 
  11.                 after(0.1) { 
  12.                     resolve(value + value) 
  13.                 } 
  14.             } 
  15.         } 
  16.         .then { value in // the "observe" previously defined 
  17.             assert(string + string == value) 
  18.             done() 
  19.         } 

如測試所見,第一個then創(chuàng)建了一個有新 value 的新Promise并返回了它。第二個then(我們前一節(jié)定義的,被稱為observe)被串聯(lián)在后面,它訪問新的 value(其將是"foofoo")。

我們很快在終端里看到錯誤。

  1. error: Promise.playground:143:10: error: value of tuple type '()' has no member 'then' 
  2.         .then { value in 
  3.          ^ 

我們必須創(chuàng)建一個then的重載,它接受一個能返回 promise 的函數(shù)。為了能夠串聯(lián)調(diào)用then,這個方法必須也返回一個promise。這個then的原型如下。

  1. func then<NewValue>(onResolved: @escaping (Value) -> Promise<NewValue>) -> Promise<NewValue> { 
  2.     // to implement 

注:細(xì)心的讀者可能已經(jīng)發(fā)現(xiàn),我們在給Promise實(shí)現(xiàn)flatMap。就如給Optional和Array定義flatMap一樣,我們也可以給Promise定義它。

困難來了。讓我們一步步看看這個“flatMap”的then要怎么實(shí)現(xiàn)。

  • 我們需要返回一個Promise
  • 誰給我們這樣一個 promise?onResolved 方法
  • 但onResolved 需要一個類型為Value的 value 為參數(shù)。我們該怎樣得到這個 value? 我們可以使用之前定義的then(或者說 “observe”) 來在其可用時訪問它

如果寫成代碼,大概如下:

  1. func then<NewValue>(onResolved: @escaping (Value) -> Promise<NewValue>) -> Promise<NewValue> { 
  2.     then { value in // the "observe" one 
  3.         let promise = onResolved(value) // `promise` is a Promise<NewValue> 
  4.         // problem: how do we return `promise` to the outside ?? 
  5.     } 
  6.     return // ??!! 

就快好了。但我們還有個小問題需要修復(fù):這個promise變量被傳遞給then的閉包所限制。我們不能將其作為函數(shù)的返回值。

我們要使用的技巧是創(chuàng)建一個包裝Promise,它將執(zhí)行我們目前所寫的代碼,然后在promise變量解決時被同時解決。換句話說,當(dāng)onResolved方法提供的 promise 被解決并從外部得到一個值,那包裝的 promise 也就被解決并得到同樣的值。

可能文字有些抽象,但如果我們寫成代碼,將看得更清楚:

  1. func then<NewValue>(onResolved: @escaping (Value) -> Promise<NewValue>) -> Promise<NewValue> { 
  2.     // We have to return a promise, so let's return a new one 
  3.     return Promise<NewValue> { resolve in 
  4.         // this is called immediately as seen in test 0. 
  5.         then { value in // the "observe" one 
  6.             let promise = onResolved(value) // `promise` is a Promise<NewValue> 
  7.             // `promise` has the same type of the Promise wrapper 
  8.             // we can make the wrapper resolves when the `promise` resolves 
  9.             // and gets a value 
  10.             promise.then { value in resolve(value) } 
  11.         } 
  12.     } 

如果我們整理一下代碼,我們將有這樣兩個方法:

  1. // observe 
  2. func then(onResolved: @escaping (Value) -> Void) { 
  3.     callbacks.append(onResolved) 
  4.     triggerCallbacksIfResolved() 
  5.  
  6. // flatMap 
  7. func then<NewValue>(onResolved: @escaping (Value) -> Promise<NewValue>) -> Promise<NewValue> { 
  8.     return Promise<NewValue> { resolve in 
  9.         then { value in 
  10.             onResolved(value).then(onResolved: resolve) 
  11.         } 
  12.     } 

最后,測試通過。

  1. • Test 3. Resolution handlers can be chained passed (1 assertions) 

串聯(lián)多個 value

如果你能給某個類型實(shí)現(xiàn)flatMap,那你就能利用flatMap為其實(shí)現(xiàn)map。對于我們的Promise來說,map該是什么樣子?

我們將使用如下測試:

  1. test(named: "4. Chaining works with non promise return values") { assert, done in 
  2.     let string: String = "foo" 
  3.     let promise = Promise<String> { resolve in 
  4.         after(0.1) { 
  5.             resolve(string) 
  6.         } 
  7.     } 
  8.     promise 
  9.         .then { value -> String in 
  10.             return value + value 
  11.         } 
  12.         .then { value in // the "observe" then 
  13.             assert(string + string == value) 
  14.             done() 
  15.         } 

注意第一個then沒有再返回一個Promise,而是將其接收的值做了一個變換。這個新的then就對應(yīng)于我們想添加的map。

編譯器報錯說我們必須實(shí)現(xiàn)此方法。

  1. error: Promise.playground:174:26: error: declared closure result 'String' is incompatible with contextual type 'Void' 
  2.         .then { value -> String in 
  3.                          ^~~~~~ 
  4.                          Void 

這個方法很接近flatMap,唯一的不同是其參數(shù)onResolved函數(shù)返回一個NewValue而不是Promise

  1. // map 
  2. func then<NewValue>(onResolved: @escaping (Value) -> NewValue) -> Promise<NewValue> { 
  3.     // to implement 

之前我們說可以利用flatMap實(shí)現(xiàn)map。在我們的情況里,我們看到我們需要返回一個Promise。如果我們使用這個“flatMap”的then,并創(chuàng)建一個promise,再以映射后的 value 來直接解決,我們就搞定了。讓我來證明之。

  1. // map 
  2. func then<NewValue>(onResolved: @escaping (Value) -> NewValue) -> Promise<NewValue> { 
  3.     return then { value in // the "flatMap" defined before 
  4.         // must return a Promise<NewValue> here 
  5.         // this promise directly resolves with the mapped value 
  6.         return Promise<NewValue> { resolve in 
  7.             let newValue = onResolved(value) 
  8.             resolve(newValue) 
  9.         } 
  10.     } 

再一次,測試通過。

  1. • Test 4. Chaining works with non promise return values passed (1 assertions) 

如果我們移除注釋,再看看我們做出了什么。我們有三個then方法的實(shí)現(xiàn),能被使用或串聯(lián)。

  1. // observe 
  2. func then(onResolved: @escaping (Value) -> Void) { 
  3.     callbacks.append(onResolved) 
  4.     triggerCallbacksIfResolved() 
  5.  
  6. // flatMap 
  7. func then<NewValue>(onResolved: @escaping (Value) -> Promise<NewValue>) -> Promise<NewValue> { 
  8.     return Promise<NewValue> { resolve in 
  9.         then { value in 
  10.             onResolved(value).then(onResolved: resolve) 
  11.         } 
  12.     } 
  13.  
  14. // map 
  15. func then<NewValue>(onResolved: @escaping (Value) -> NewValue) -> Promise<NewValue> { 
  16.     return then { value in 
  17.         return Promise<NewValue> { resolve in 
  18.             resolve(onResolved(value)) 
  19.         } 
  20.     } 

使用示例

實(shí)現(xiàn)告一段落。我們的Promise類已足夠完整來展示我們能夠用它做什么。

假設(shè)我們的app有一些用戶,結(jié)構(gòu)如下:

  1. struct User { 
  2.     let id: Int 
  3.     let name: String 

假設(shè)我們還有兩個方法,一個獲取用戶id列表,另一個使用id獲取某個用戶。而且假設(shè)我們想顯示第一個用戶的名字。

通過我們的實(shí)現(xiàn),我們可以這樣做,使用之前定義的這三個then。

  1. func fetchIds() -> Promise<[Int]> { 
  2.     ... 
  3.  
  4. func fetchUser(id: Int) -> Promise<User> { 
  5.     ... 
  6.  
  7. fetchIds() 
  8.     .then { ids in // flatMap 
  9.         return fetchUser(id: ids[0]) 
  10.     } 
  11.     .then { user in // map 
  12.         return user.name 
  13.     } 
  14.     .then { name in // observe 
  15.         print(name
  16.     } 

代碼變得十分易讀、簡潔,而且沒有嵌套。

結(jié)論本文結(jié)束,希望你喜歡它。

參考資料

[1]gist:

https://gist.github.com/felginep/039ca3b21e4f0cabb1c06126d9164680

[2]Promises in Swift by Khanlou:

http://khanlou.com/2016/08/promises-in-swift/

[3]JavaScript Promises … In Wicked Detail:

https://www.mattgreer.org/articles/promises-in-wicked-detail/

[4]PromiseKit 6 Release Details:

https://promisekit.org/news/2018/02/PromiseKit-6.0-Released/

[5]TDD Implementation of Promises in JavaScript:

https://www.youtube.com/watch?v=C3kUMPtt4hY

[6]Implementing Promises in Swift:

https://felginep.github.io/2019-01-06/implementing-promises-in-swift

本文轉(zhuǎn)載自微信公眾號「Swift社區(qū)」

 

責(zé)任編輯:姜華 來源: Swift社區(qū)
相關(guān)推薦

2023-12-21 17:11:21

Containerd管理工具命令行

2022-12-20 07:39:46

2023-11-20 08:18:49

Netty服務(wù)器

2023-07-31 08:18:50

Docker參數(shù)容器

2021-05-29 10:11:00

Kafa數(shù)據(jù)業(yè)務(wù)

2022-11-11 19:09:13

架構(gòu)

2023-11-06 08:16:19

APM系統(tǒng)運(yùn)維

2022-07-18 21:53:46

RocketMQ廣播消息

2022-02-24 07:34:10

SSL協(xié)議加密

2023-10-27 08:15:45

2023-11-08 08:15:48

服務(wù)監(jiān)控Zipkin

2024-10-10 09:12:10

Spring接口初始化

2019-06-13 21:31:19

AI

2024-05-22 09:45:49

2021-09-13 22:34:56

區(qū)塊鏈新基建數(shù)字化轉(zhuǎn)型

2023-03-06 21:29:41

mmap技術(shù)操作系統(tǒng)

2020-11-27 09:40:53

Rollup前端代碼

2022-04-08 09:01:14

CSS自定義屬性前端

2022-05-16 10:49:28

網(wǎng)絡(luò)協(xié)議數(shù)據(jù)

2022-02-28 12:07:56

RxJS函數(shù)式
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號