• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

PromiseKit基本使用和源码

武飞扬头像
不凡的凡
帮助1

     Promise处理一系列异步操作的应用框架,能够保证顺序执行一系列异步操作,当出错时可以通过catch捕获错误进行处理。Promise框架也是很好的诠释了swift的面相协议编程以及函数式编程

两种类型 1Promise,2Guarantee 其中Guarantee没有实现 CatchMixin 协议,不能捕获错误,他是不允许抛出错误,常用的就是第一种类型,便于错误处理。Promise是承诺执行,有可能不执行;而guarantee是保证,保证一定执行

基本使用形式:

  1.  
    func threeRequest111() {
  2.  
    firstly {
  3.  
    request1(with: ["test1": "first"])
  4.  
    }
  5.  
    .then { (v) -> Promise<NSDictionary> in
  6.  
    print("🍀", v)
  7.  
    return self.request2(para: ["test2": "second"])
  8.  
    }
  9.  
    .then { (v) -> Promise<NSDictionary> in
  10.  
    print("🍀🍀", v)
  11.  
    return self.request3(para: ["test3": "third"])
  12.  
    }
  13.  
    .map({ (dic) -> [String:String] in
  14.  
    if let dic1 = dic as? [String:String]{
  15.  
    return dic1
  16.  
    }else{
  17.  
    return [String:String]()
  18.  
    }
  19.  
    }).done({ (dic) in
  20.  
    print(dic)
  21.  
    })
  22.  
    .catch { (error) in
  23.  
    print(error.localizedDescription)
  24.  
     
  25.  
    }.finally {
  26.  
    print("finaly")
  27.  
    }
  28.  
    }

学新通

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函数

  1.  
    func then<U: Thenable>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) throws -> U) -> Promise<U.T> {
  2.  
    let rp = Promise<U.T>(.pending)
  3.  
    pipe {//向上一个promise中添加任务
  4.  
    switch $0 {
  5.  
    case .fulfilled(let value):
  6.  
    on.async(flags: flags) {
  7.  
    do {
  8.  
    let rv = try body(value)
  9.  
    guard rv !== rp else { throw PMKError.returnedSelf }
  10.  
    rv.pipe(to: rp.box.seal)
  11.  
    } catch {
  12.  
    rp.box.seal(.rejected(error))
  13.  
    }
  14.  
    }
  15.  
    case .rejected(let error):
  16.  
    rp.box.seal(.rejected(error))
  17.  
    }
  18.  
    }
  19.  
    return rp
  20.  
    }

学新通

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)) ->

  1.  
    override func seal(_ value: T) {
  2.  
    var handlers: Handlers<T>!
  3.  
    barrier.sync(flags: .barrier) {
  4.  
    guard case .pending(let _handlers) = self.sealant else {
  5.  
    return // already fulfilled!
  6.  
    }
  7.  
    handlers = _handlers
  8.  
    self.sealant = .resolved(value)
  9.  
    }
  10.  
    if let handlers = handlers {
  11.  
    handlers.bodies.forEach{ $0(value) }
  12.  
    }
  13.  
    }
  14.  
    带着结果值执行handlers.bodies里边的任务(也就是下一个then中的block)实际上就是上边天加进去的pipe闭包:
  15.  
     
  16.  
    pipe {//向上一个promise中添加任务
  17.  
     
  18.  
    switch $0 {
  19.  
     
  20.  
    case .fulfilled(let value):
  21.  
     
  22.  
    on.async(flags: flags) {
  23.  
     
  24.  
    do {
  25.  
     
  26.  
    let rv = try body(value)
  27.  
     
  28.  
    guard rv !== rp else { throw PMKError.returnedSelf }
  29.  
     
  30.  
    rv.pipe(to: rp.box.seal)//执行rp.handlers.foreach这个任务添加到rv.handlers
  31.  
     
  32.  
    } catch {
  33.  
     
  34.  
    rp.box.seal(.rejected(error))
  35.  
     
  36.  
    }
  37.  
     
  38.  
    }
  39.  
     
  40.  
    case .rejected(let error):
  41.  
     
  42.  
    rp.box.seal(.rejected(error))
  43.  
     
  44.  
    }
  45.  
     
  46.  
    }

学新通

这里边又个比较绕的东西就是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它有默认实现:

  1.  
    @discardableResult
  2.  
    func `catch`(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) -> Void) -> PMKFinalizer {
  3.  
    let finalizer = PMKFinalizer()
  4.  
    pipe {
  5.  
    switch $0 {
  6.  
    case .rejected(let error):
  7.  
    guard policy == .allErrors || !error.isCancelled else {
  8.  
    fallthrough
  9.  
    }
  10.  
    on.async(flags: flags) {
  11.  
    body(error)
  12.  
    finalizer.pending.resolve(())
  13.  
    }
  14.  
    case .fulfilled:
  15.  
    finalizer.pending.resolve(())
  16.  
    }
  17.  
    }
  18.  
    return finalizer
  19.  
    }

学新通

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

  1.  
    public func firstly<U: Thenable>(execute body: () throws -> U) -> Promise<U.T> {
  2.  
    do {
  3.  
    let rp = Promise<U.T>(.pending)
  4.  
    try body().pipe(to: rp.box.seal)//执行body,创建Promise,返回后执行pipe(外部可能是异步的耗时操作,所以会先执行pipe(to),return rp,接着是外部的.then函数等)
  5.  
    return rp
  6.  
    } catch {
  7.  
    return Promise(error: error)
  8.  
    }
  9.  
    }

4.when函数,主要是实现前边几个任务同时进行,等他们都执行完,精心后边的顺序执行任务。

基本使用方式:

  1.  
    //request1和request2,并行执行,都执行完再执行request3;参数是个promise数组,多个任务同时执行
  2.  
    when(fulfilled: [request1(with: ["para1":"hello"]),request2(para: ["para2":"nihao"])])
  3.  
    .then { (dic) -> Promise<NSDictionary> in
  4.  
    self.request3(para: ["uhu":"nih"])
  5.  
    }.catch { (error) in
  6.  
    print(error.localizedDescription)
  7.  
    }
  8.  
    //promises数组中是结果不同类型的promise,最多支持5种不同类型的Promise
  9.  
    when(fulfilled: request1(with: ["para1":"hello"]), request4())
  10.  
    .then { (arg0) -> Promise<[String:String]> in
  11.  
    let (dic, str) = arg0
  12.  
    return Promise<[String:String]>(resolver: { (res) in
  13.  
    res.fulfill([str : "\(dic)"])
  14.  
    })
  15.  
    }.catch { (error) in
  16.  
    print(error.localizedDescription)
  17.  
    }
  18.  
    查看其源码,通过两个Int值,表示已经执行完的任务数和总共的任务数
  19.  
    private func _when<U: Thenable>(_ thenables: [U]) -> Promise<Void> {
  20.  
    var countdown = thenables.count
  21.  
    guard countdown > 0 else {
  22.  
    return .value(Void())
  23.  
    }
  24.  
     
  25.  
    let rp = Promise<Void>(.pending)
  26.  
     
  27.  
    #if PMKDisableProgress || os(Linux)
  28.  
    var progress: (completedUnitCount: Int, totalUnitCount: Int) = (0, 0)
  29.  
    #else
  30.  
    let progress = Progress(totalUnitCount: Int64(thenables.count))
  31.  
    progress.isCancellable = false
  32.  
    progress.isPausable = false
  33.  
    #endif
  34.  
     
  35.  
    let barrier = DispatchQueue(label: "org.promisekit.barrier.when", attributes: .concurrent)
  36.  
     
  37.  
    for promise in thenables {
  38.  
    promise.pipe { result in
  39.  
    barrier.sync(flags: .barrier) {
  40.  
    switch result {
  41.  
    case .rejected(let error):
  42.  
    //如果是pending(等待)状态,将错误往下传递,这个判断确保了几个并行的任务
  43.  
    //只有第一个出错的任务它错误往下传递,因为一旦出错其他的任何任务都再无意义
  44.  
    if rp.isPending {
  45.  
    progress.completedUnitCount = progress.totalUnitCount
  46.  
    rp.box.seal(.rejected(error))
  47.  
    }
  48.  
    case .fulfilled:
  49.  
    //这个条件确保了,如果几个并行的任务有一个已经出错,后来正确完成的任务到这里不再往下传递
  50.  
    guard rp.isPending else { return }
  51.  
    progress.completedUnitCount = 1
  52.  
    countdown -= 1
  53.  
    if countdown == 0 {
  54.  
    rp.box.seal(.fulfilled(()))
  55.  
    }
  56.  
    }
  57.  
    }
  58.  
    }
  59.  
    }
  60.  
     
  61.  
    return rp
  62.  
    }

学新通

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提供的其他函数

  1.  
    Map 转换函数,将结果进行转换
  2.  
    public func map<U>(on: DispatchQueue? = default, flags: DispatchWorkItemFlags? = default, _ transform: @escaping (Self.T) throws -> U) -> PromiseKit.Promise<U>
  3.  
    done函数,done函数和then函数的区别就是是block返回值是void,只是顺序执行,二不需要上一步的结果值是用done函数
  4.  
    func done(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) throws -> Void) -> Promise<Void>
  5.  
    Get函数,他和done差不多,只是会自动的返回上部的结果值
  6.  
    func get(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping (T) throws -> Void) -> Promise<T>
  7.  
    tap函数,他会返回一个Result<T>,你可以从这里查看返回的值,而不会对整个链产生任何副作用
  8.  
    func tap(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(Result<T>) -> Void) -> Promise<T>
  9.  
    asVoid函数,它返回一个新的promise,与上一个promise连起来,而上一个promise的值被抛弃
  10.  
    func asVoid() -> Promise<Void>
  11.  
     
  12.  
    还有一些当结果值是Sequence(也就是数组)时的函数,对数组的一些理,和数组的一些高阶函数差不多
  13.  
    public extension Thenable where T: Sequence
  14.  
    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,不收到回掉不会释放

  1.  
    extension NSObject {
  2.  
    public func observe(_: PMKNamespacer, keyPath: String) -> Guarantee<Any?> {
  3.  
    return Guarantee { KVOProxy(observee: self, keyPath: keyPath, resolve: $0) }
  4.  
    }
  5.  
    }
  6.  
     
  7.  
    private class KVOProxy: NSObject {
  8.  
    var retainCycle: KVOProxy?
  9.  
    let fulfill: (Any?) -> Void
  10.  
     
  11.  
    @discardableResult
  12.  
    init(observee: NSObject, keyPath: String, resolve: @escaping (Any?) -> Void) {
  13.  
    fulfill = resolve
  14.  
    super.init()
  15.  
    observee.addObserver(self, forKeyPath: keyPath, options: NSKeyValueObservingOptions.new, context: pointer)
  16.  
    retainCycle = self
  17.  
    //持有自己造成循环引用,不收到回掉不会释放
  18.  
    }
  19.  
     
  20.  
    fileprivate override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
  21.  
    if let change = change, context == pointer {
  22.  
    defer { retainCycle = nil }//延时执行,所在作用域内最后执行,收到回掉后才进行释放
  23.  
    fulfill(change[NSKeyValueChangeKey.newKey])
  24.  
    if let object = object as? NSObject, let keyPath = keyPath {
  25.  
    object.removeObserver(self, forKeyPath: keyPath)
  26.  
    }
  27.  
    }
  28.  
    }
  29.  
     
  30.  
    private lazy var pointer: UnsafeMutableRawPointer = {
  31.  
    return Unmanaged<KVOProxy>.passUnretained(self).toOpaque()
  32.  
    }()
  33.  
    }

学新通

附带2,框架对alamofire做了了一些extension,请求的返回值可以直接是一个promise,进行链式操作

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgbkkkf
系列文章
更多 icon
同类精品
更多 icon
继续加载