Promise处理一系列异步操做的应用框架,可以保证顺序执行一系列异步操做,当出错时能够经过catch捕获错误进行处理。Promise框架也是很好的诠释了swift的面相协议编程以及函数式编程编程
两种类型 1Promise,2Guarantee 其中Guarantee没有实现 CatchMixin 协议,不能捕获错误,他是不容许抛出错误,经常使用的就是第一种类型,便于错误处理。Promise是承诺执行,有可能不执行;而guarantee是保证,保证必定执行swift
基本使用形式:api
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) inpromise
Alamofire.request("https://httpbin.org/get", method: .get, parameters: parameters).validate().responseJSON() { (response) in闭包
switch response.result {app
case .success(let dict):框架
delay(time: 1, task: {异步
resolver.fulfill(dict as! NSDictionary)async
})
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,进行链式操做