整體思路
鏈式非同步思路 每個Promise中儲存下一個Promise的執行邏輯並把當前操作返回值傳遞給下一個Promise,已經執行的seal狀態變成.resolved,沒有就加到.pendding(handlers)中handlers的bodies裡面等待執行,下一個promise根據上一個promise的state狀態來進行下一步,把自己的處理流程加到上一個promise處理流程的後面
每個promise例項通過state: State<T> 儲存當前promise的狀態
seal表示當前是否已經執行
- .panding表示沒有執行,正在等待執行
- .resolved表示已經完成,並且儲存了返回值
fulfill履行
reject拒絕
then成功時呼叫
catch失敗時呼叫
State.swift
兩個重要的列舉
Seal是用來儲存處理狀態
enum Seal<T> {
case pending(Handlers<T>) // 等待處理,Handlers用來儲存當前promise下一個處理流程
case resolved(Resolution<T>)// 已經處理有返回值,Resolution封裝正確和錯誤的返回值
}
複製程式碼
Resolution封裝返回值
enum Resolution<T> {
case fulfilled(T) // 正確的返回值
case rejected(Error, ErrorConsumptionToken) // 錯誤的返回值
init(_ error: Error) {
self = .rejected(error, ErrorConsumptionToken(error))
}
}
複製程式碼
Handlers用來儲存當前promise下一個處理流程,bodies儲存的閉包就是接下來要處理的邏輯
class Handlers<T>: Sequence {
var bodies: [(Resolution<T>) -> Void] = []
func append(_ body: @escaping (Resolution<T>) -> Void) {
bodies.append(body)
}
func makeIterator() -> IndexingIterator<[(Resolution<T>) -> Void]> {
return bodies.makeIterator()
}
var count: Int {
return bodies.count
}
}
複製程式碼
seal屬性:用來儲存處理狀態
seal是在以下閉包中改變
required init(resolver: inout ((Resolution<T>) -> Void)!) {
seal = .pending(Handlers<T>())
super.init()
// 閉包的實現
resolver = { resolution in
var handlers: Handlers<T>?
self.barrier.sync(flags: .barrier) {
if case .pending(let hh) = self.seal {
self.seal = .resolved(resolution)
handlers = hh
}
}
if let handlers = handlers {
for handler in handlers {
handler(resolution)
}
}
}
}
複製程式碼
pipe方法根據seal的狀態來判斷是立即返回還是稍後處理
final func pipe(_ body: @escaping (Resolution<T>) -> Void) {
get { seal in
switch seal {
case .pending(let handlers):
handlers.append(body)
case .resolved(let resolution):
body(resolution)
}
}
}
複製程式碼
Promise.swift
state: State<T> 儲存當前promise的狀態
初始化方法1,第一個promise初始化呼叫此方法,根據外面呼叫fulfill或者reject,來更新state屬性
required public init(resolvers: (_ fulfill: @escaping (T) -> Void, _ reject: @escaping (Error) -> Void) throws -> Void) {
var resolve: ((Resolution<T>) -> Void)!
do {
state = UnsealedState(resolver: &resolve)
try resolvers({ resolve(.fulfilled($0)) }, { error in
#if !PMKDisableWarnings
if self.isPending {
resolve(Resolution(error))
} else {
NSLog("PromiseKit: warning: reject called on already rejected Promise: \(error)")
}
#else
resolve(Resolution(error))
#endif
})
} catch {
resolve(Resolution(error))
}
}
複製程式碼
初始化方法2,由Promise.then呼叫,在鏈式語法中自動初始化
init(sealant: (@escaping (Resolution<T>) -> Void) -> Void) {
var resolve: ((Resolution<T>) -> Void)!
state = UnsealedState(resolver: &resolve)
sealant(resolve)
}
複製程式碼
then方法,呼叫初始化方法2進行下一個promise的初始化
public func then<U>(on q: DispatchQueue = .default, execute body: @escaping (T) throws -> U) -> Promise<U> {
return Promise<U> { resolve in
state.then(on: q, else: resolve) { value in
resolve(.fulfilled(try body(value)))
}
}
}
複製程式碼
程式碼邏輯分析
分析以下程式碼呼叫邏輯
API.getHomeInfo().then { res in
print(res)
}.catch { (error) in
print(error)
}
複製程式碼
API.getHomeInfo()初始化一個promise,state儲存了promise的狀態,當呼叫fulfill或者reject的時候,就會呼叫state中resolver閉包的實現,將seal的狀態從.pending變成.resolved,並將值傳遞給.resolved,將.pending中Handlers取出,將值傳遞給Handlers的bodies閉包陣列來執行
return Promise<T> { fulfill, reject in
requestByIgnoringCodeEvent(config) { (requestResult) in
if requestResult.isSuccess {
fulfill(requestResult)
} else {
let message = requestResult.message ?? "伺服器返回錯誤"
let error = NSError(domain: "Network Error", code: 1,
userInfo: [NSLocalizedDescriptionKey: message])
reject(error)
}
}
}
複製程式碼
then也是初始化一個promise例項,呼叫初始化方法2,將state中resolve閉包傳遞到外面來根據上一個promise的state.then來進行進行操作
public func then<U>(on q: DispatchQueue = .default, execute body: @escaping (T) throws -> U) -> Promise<U> {
return Promise<U> { resolve in
state.then(on: q, else: resolve) { value in
resolve(.fulfilled(try body(value)))
}
}
}
複製程式碼
state.then呼叫的pipe函式
pipe函式呼叫get函式
get函式先判斷seal的狀態,如果當前promise沒有呼叫fullfill或者reject,說明還沒有返回值過來,那seal的狀態就還是.pending就執行緒就等待前面的完成,有返回值seal狀態就變成了.resolved,最後將seal狀態傳遞閉包
pipe函式處理get函式傳遞給來的seal狀態,.pending就接受的閉包新增到handlers的bidies陣列裡面,後面合適的時候在執行閉包,如果是.resolved就直接把.resolved中值傳遞給閉包引數
final func then<U>(on q: DispatchQueue, else rejecter: @escaping (Resolution<U>) -> Void, execute body: @escaping (T) throws -> Void) {
pipe { resolution in
switch resolution {
case .fulfilled(let value):
contain_zalgo(q, rejecter: rejecter) {
// 觸發下個流程的開始
try body(value)
}
case .rejected(let error, let token):
rejecter(.rejected(error, token))
}
}
}
final func pipe(_ body: @escaping (Resolution<T>) -> Void) {
get { seal in
switch seal {
case .pending(let handlers):
handlers.append(body)
case .resolved(let resolution):
body(resolution)
}
}
}
override func get(body: @escaping (Seal<T>) -> Void) {
var sealed = false
barrier.sync {
switch self.seal {
case .resolved:
sealed = true
case .pending:
sealed = false
}
}
if !sealed {
barrier.sync(flags: .barrier) {
switch (self.seal) {
case .pending:
body(self.seal)
case .resolved:
sealed = true // welcome to race conditions
}
}
}
if sealed {
body(seal) // as much as possible we do things OUTSIDE the barrier_sync
}
}
複製程式碼
then函式處理pipe函式傳遞過來的返回值,正常呼叫body(value),異常呼叫rejecter(.rejected(error, token))
promise.then函式處理state.then傳遞過來的引數,在回撥promise的state中初始化的閉包,更新state中seal的狀態
resolver = { resolution in
var handlers: Handlers<T>?
self.barrier.sync(flags: .barrier) {
if case .pending(let hh) = self.seal {
self.seal = .resolved(resolution)
handlers = hh
}
}
if let handlers = handlers {
for handler in handlers {
handler(resolution)
}
}
}
複製程式碼
catch邏輯
promise.catch呼叫state.catch
state.catch呼叫pipe函式
pipe函式呼叫get函式
get函式在進行狀態判斷,返回當前self.seal狀態
pipe函式處理get返回的seal狀態,判斷為.pending,將body新增到handlers的bodies陣列中稍後處理,上一步在更新state中seal狀態時候,會將.pending中handles中的bodies陣列拿出來執行,這個時候就會執行state.catch方法傳入的閉包
promise.catch函式處理state.catch返回的引數,正確就不執行,錯誤執行body閉包,body就是自己寫的錯誤處理邏輯
// Promise中的catch方法
@discardableResult
public func `catch`(on q: DispatchQueue = .default, policy: CatchPolicy = .allErrorsExceptCancellation, execute body: @escaping (Error) -> Void) -> Promise {
state.catch(on: q, policy: policy, else: { _ in }, execute: body)
return self
}
// State中的catch方法
final func `catch`(on q: DispatchQueue, policy: CatchPolicy, else resolve: @escaping (Resolution<T>) -> Void, execute body: @escaping (Error) throws -> Void) {
pipe { resolution in
switch (resolution, policy) {
case (.fulfilled, _):
resolve(resolution)
case (.rejected(let error, _), .allErrorsExceptCancellation) where error.isCancelledError:
resolve(resolution)
case (let .rejected(error, token), _):
contain_zalgo(q, rejecter: resolve) {
token.consumed = true
try body(error)
}
}
}
}
複製程式碼