Promise處理一系列異步操作的應用框架,能夠保證順序執行一系列異步操作,當出錯時可以通過catch捕獲錯誤進行處理,Promise框架也是很好的詮釋了swift的面相協議編程以及函式式編程
兩種型別 1Promise,2Guarantee 其中Guarantee沒有實作 CatchMixin 協議,不能捕獲錯誤,他是不允許拋出錯誤,常用的就是第一種型別,便于錯誤處理,Promise是承諾執行,有可能不執行;而guarantee是保證,保證一定執行
基本使用形式:
func threeRequest111() { firstly { request1(with: ["test1": "first"]) } .then { (v) -> Promise<NSDictionary> in print("??", v) return self.request2(para: ["test2": "second"]) } .then { (v) -> Promise<NSDictionary> in print("????", v) return self.request3(para: ["test3": "third"]) } .map({ (dic) -> [String:String] in if let dic1 = dic as? [String:String]{ return dic1 }else{ return [String:String]() } }).done({ (dic) in print(dic) }) .catch { (error) in print(error.localizedDescription) }.finally { print("finaly") } }
func request1(with parameters: [String: String]) -> Promise<(NSDictionary)> {
return Promise<NSDictionary>(resolver: { (resolver) in
Alamofire.request("https://httpbin.org/get", method: .get, parameters: parameters).validate().responseJSON() { (response) in
switch response.result {
case .success(let dict):
delay(time: 1, task: {
resolver.fulfill(dict as! NSDictionary)
})
case .failure(let error):
resolver.reject(error)
}
}
})
}
func request2(para:[String:String]) -> Promise<NSDictionary> {
return request1(with: para)
}
func request3(para:[String:String]) -> Promise<NSDictionary> {
return request1(with: para)
}
原始碼決議
一 開始帶著問題去想研究下原始碼
1.如何保證一系列block順序執行的呢
把外部傳入的thenBlock等保存起來了,保存到一個陣列中,handlers.append(to),當自己的任務執行完去執行存在陣列的任務
2.閉包中回傳值promise 如何與 firstly函式中的promise聯系起來的
rv.pipe(to: rp.box.seal)
二,Promise 主要函式
1.then函式
func then<U: Thenable>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) throws -> U) -> Promise<U.T> { let rp = Promise<U.T>(.pending) pipe {//向上一個promise中添加任務 switch $0 { case .fulfilled(let value): on.async(flags: flags) { do { let rv = try body(value) guard rv !== rp else { throw PMKError.returnedSelf } rv.pipe(to: rp.box.seal) } catch { rp.box.seal(.rejected(error)) } } case .rejected(let error): rp.box.seal(.rejected(error)) } } return rp }
then函式中將pipe閉包(包括了外部需要執行的閉包)添加進上一個promise.box.handers中:
handlers.append(to)
to就是then函式中的pipe閉包,并且添加的時候時用柵欄函式同步添加的,保證了任務的順序執行
barrier.sync(flags: .barrier) {//柵欄同步
當上一個promise中的閉包(外部耗時任務)執行完,resever呼叫fufill:
resolver.fulfill(T) -> box.seal(.fulfilled(value)) ->
override func seal(_ value: T) { var handlers: Handlers<T>! barrier.sync(flags: .barrier) { guard case .pending(let _handlers) = self.sealant else { return // already fulfilled! } handlers = _handlers self.sealant = .resolved(value) } if let handlers = handlers { handlers.bodies.forEach{ $0(value) } } }帶著結果值執行handlers.bodies里邊的任務(也就是下一個then中的block)實際上就是上邊天加進去的pipe閉包: pipe {//向上一個promise中添加任務 switch $0 { case .fulfilled(let value): on.async(flags: flags) { do { let rv = try body(value) guard rv !== rp else { throw PMKError.returnedSelf } rv.pipe(to: rp.box.seal)//執行rp.handlers.foreach這個任務添加到rv.handlers } catch { rp.box.seal(.rejected(error)) } } case .rejected(let error): rp.box.seal(.rejected(error)) } }
這里邊又個比較繞的東西就是switch $0 是Result<T>型別,而呼叫的地方handlers.bodies.forEach{ $0(value) },傳入的value是T型別,不匹配,繞了一圈看了一下,初始化resolve時T表示了ResultT,這樣就時匹配的沒錯
我們知道then函式block中需要回傳一個Promise:rv,而then函式中有創建了一個Promise:rp,傳入下一個then函式中,下面以相鄰的兩個then函式再簡化的理解一下then{rv1:Promise}.then{rv2:promise}
rv1的handler中存的是rp1.box.seal也就是是否要執行rv2所在的那個pipe

2.catch 錯誤捕獲函式,為什么promise連中無論哪一環節報錯,都能走到catch中去呢
catch定義在CatchMixin協議中,promise是實作了這個協議的,catch它有默認實作:
@discardableResult func `catch`(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) -> Void) -> PMKFinalizer { let finalizer = PMKFinalizer() pipe { switch $0 { case .rejected(let error): guard policy == .allErrors || !error.isCancelled else { fallthrough } on.async(flags: flags) { body(error) finalizer.pending.resolve(()) } case .fulfilled: finalizer.pending.resolve(()) } } return finalizer }
catch一般在promise鏈中的最后或者finally前邊,所以它的回傳值是PMKFinalizer
通過pipe把pipe的內容添加到了上一個promise的handels中
當promise鏈中任何一環執行reject(error)時,執行下一個promise中的seal
rp.box.seal(.rejected(error))
順著promise鏈一直往下走,每一個都是執行這個,直到catch,走catch中的代碼任務
3.firstly,了解了t很函式之后再看firstly就容易理解多了,它比then不同地一點是,它是先執行因為他前邊沒有promise,它一個函式而不是promise的方法,回傳值和then一樣,是個promise
public func firstly<U: Thenable>(execute body: () throws -> U) -> Promise<U.T> { do { let rp = Promise<U.T>(.pending) try body().pipe(to: rp.box.seal)//執行body,創建Promise,回傳后執行pipe(外部可能是異步的耗時操作,所以會先執行pipe(to),return rp,接著是外部的.then函式等) return rp } catch { return Promise(error: error) }}
4.when函式,主要是實作前邊幾個任務同時進行,等他們都執行完,精心后邊的順序執行任務,
基本使用方式:
//request1和request2,并行執行,都執行完再執行request3;引數是個promise陣列,多個任務同時執行 when(fulfilled: [request1(with: ["para1":"hello"]),request2(para: ["para2":"nihao"])]) .then { (dic) -> Promise<NSDictionary> in self.request3(para: ["uhu":"nih"]) }.catch { (error) in print(error.localizedDescription) } //promises陣列中是結果不同型別的promise,最多支持5種不同型別的Promise when(fulfilled: request1(with: ["para1":"hello"]), request4()) .then { (arg0) -> Promise<[String:String]> in let (dic, str) = arg0 return Promise<[String:String]>(resolver: { (res) in res.fulfill([str : "\(dic)"]) }) }.catch { (error) in print(error.localizedDescription) }查看其原始碼,通過兩個Int值,表示已經執行完的任務數和總共的任務數private func _when<U: Thenable>(_ thenables: [U]) -> Promise<Void> { var countdown = thenables.count guard countdown > 0 else { return .value(Void()) } let rp = Promise<Void>(.pending)#if PMKDisableProgress || os(Linux) var progress: (completedUnitCount: Int, totalUnitCount: Int) = (0, 0)#else let progress = Progress(totalUnitCount: Int64(thenables.count)) progress.isCancellable = false progress.isPausable = false#endif let barrier = DispatchQueue(label: "org.promisekit.barrier.when", attributes: .concurrent) for promise in thenables { promise.pipe { result in barrier.sync(flags: .barrier) { switch result { case .rejected(let error): //如果是pending(等待)狀態,將錯誤往下傳遞,這個判斷確保了幾個并行的任務 //只有第一個出錯的任務它錯誤往下傳遞,因為一旦出錯其他的任何任務都再無意義 if rp.isPending { progress.completedUnitCount = progress.totalUnitCount rp.box.seal(.rejected(error)) } case .fulfilled: //這個條件確保了,如果幾個并行的任務有一個已經出錯,后來正確完成的任務到這里不再往下傳遞 guard rp.isPending else { return } progress.completedUnitCount += 1 countdown -= 1 if countdown == 0 { rp.box.seal(.fulfilled(())) } } } } } return rp}
5.race函式,和when函式對比來看,race引數也是幾個promise,不同的是它只有其中一個回傳成功就往下傳遞繼續promise鏈,不用等這幾個任務全執行完,每個執行完了都往下走一遍promise鏈這種需求可能應用的少一點
private func _race<U: Thenable>(_ thenables: [U]) -> Promise<U.T> {
let rp = Promise<U.T>(.pending)
for thenable in thenables {
thenable.pipe(to: rp.box.seal)
}
return rp
}
二.看一下Promise提供的其他函式
Map 轉換函式,將結果進行轉換public func map<U>(on: DispatchQueue? = default, flags: DispatchWorkItemFlags? = default, _ transform: @escaping (Self.T) throws -> U) -> PromiseKit.Promise<U>done函式,done函式和then函式的區別就是是block回傳值是void,只是順序執行,二不需要上一步的結果值是用done函式func done(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) throws -> Void) -> Promise<Void> Get函式,他和done差不多,只是會自動的回傳上部的結果值 func get(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping (T) throws -> Void) -> Promise<T>tap函式,他會回傳一個Result<T>,你可以從這里查看回傳的值,而不會對整個鏈產生任何副作用func tap(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(Result<T>) -> Void) -> Promise<T>asVoid函式,它回傳一個新的promise,與上一個promise連起來,而上一個promise的值被拋棄func asVoid() -> Promise<Void>還有一些當結果值是Sequence(也就是陣列)時的函式,對陣列的一些理,和陣列的一些高階函式差不多public extension Thenable where T: Sequence func mapValues<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U]>
附帶1,框架還封裝了一個KVO實作KVOProxy,為Guarantee打造的一個KVO,任何一個類都可以添加一個觀察者,當收到觀察屬性變化時窒執行guarantee的內容,guarantee是一個保證,一定會執行,所以KVO中,KVOProxy自己持有自己,retainCycle = self,不收到回掉不會釋放
extension NSObject { public func observe(_: PMKNamespacer, keyPath: String) -> Guarantee<Any?> { return Guarantee { KVOProxy(observee: self, keyPath: keyPath, resolve: $0) } }}private class KVOProxy: NSObject { var retainCycle: KVOProxy? let fulfill: (Any?) -> Void @discardableResult init(observee: NSObject, keyPath: String, resolve: @escaping (Any?) -> Void) { fulfill = resolve super.init() observee.addObserver(self, forKeyPath: keyPath, options: NSKeyValueObservingOptions.new, context: pointer) retainCycle = self //持有自己造成回圈參考,不收到回掉不會釋放 } fileprivate override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { if let change = change, context == pointer { defer { retainCycle = nil }//延時執行,所在作用域內最后執行,收到回掉后才進行釋放 fulfill(change[NSKeyValueChangeKey.newKey]) if let object = object as? NSObject, let keyPath = keyPath { object.removeObserver(self, forKeyPath: keyPath) } } } private lazy var pointer: UnsafeMutableRawPointer = { return Unmanaged<KVOProxy>.passUnretained(self).toOpaque() }()}
附帶2,框架對alamofire做了了一些extension,請求的回傳值可以直接是一個promise,進行鏈式操作
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/7486.html
標籤:iOS
上一篇:iOS:探究視圖控制器的轉場影片
