美文网首页SwiftSwift
swift PromiseKit入门 - promise war

swift PromiseKit入门 - promise war

作者: yiangdea | 来源:发表于2018-10-18 21:01 被阅读220次

    PromiseKit是个啥

    官方描述:

    Promises simplify asynchronous programming, freeing you up to focus on the more important things. They are easy to learn, easy to master and result in clearer, more readable code. Your co-workers will thank you.

    PromiseKit本质上是对promise模式的实现,我的个人理解是: 将异步转化成同步。
    比如:
    A是一个闭包(俗称回调),当A初始化的时候在当前文件的第10行。
    然后当A调用的时候,在当前文件的第100行。
    当别人看代码的时候,看到了第10行的A初始化, 然后就要跟踪到第100行去看A的调用。
    那么。。如果一个流程过于复杂。
    同时有A操作,B操作,C操作。并且同时为异步。
    那么别人看你的代码就是:
    A(初始化) -> A(调用)-> B(初始化)-> B(调用) -> C(初始化) -> C(调用)
    更可怕的在于,,任意一个调用如果报error,要有足够的报错信息
    并且要从log里看出来报错的地方。
    这个时候如果用PromiseKit模式,就变成了:

    A初始化
    B初始化
    C初始化
    firstly {
      A调用
    }.then {
      B调用
    }.then {
      C调用
    }.catch {
      报错:根据A、B、C的报错可以判断出error点
    }
    

    这就是经典的promise模式,看着很像响应式框架(RX或RAC)。
    用一连串的调用规范了异步流程的耦合。
    相比较来讲,PromiseKit更为轻便易用。
    缺点也同样明显,无法像React那样很细节的监听每一步的状态。

    包装Promise

    将一个异步操作,包装成为一个可以使用promise流程的对象,比如:
    步骤一共分为:

    • 确定返回值的类型,代码中给我使用了tuple: (Bool, String)
    • 实现并包装Promise()
    • 调用fulfill和reject,如果不调用,主流程就无法继续进行
      以下为实例代码:
    func loginProto(loginInfo: LoginInfo) -> Promise<(Bool, String)> {
            return Promise(resolver: { (resolver) in
                resultBack.loginResult = { [weak self] (res, des) in
                    guard let `self` = self else { return }
                    if res {
                        resolver.fulfill((res, des ?? ""))
                    } else {
                        resolver.reject(YoungError(description: "登陆失败"))
                    }
                    self.resultBack.loginResult = nil
                }
                loginStatusOrInfo.currentLoginInfo = loginInfo
                among.proInstance.login(loginInfo)
            })
        }
    

    func loginDeal(res: (Bool, String)) -> Promise<Bool> {
            return Promise(resolver: { (resolver) in
                self.loginResWithUIDeal(isSuccess: res.0)
                resolver.fulfill(res.0)
            })
        }
    

    这样就包装好了两个promise任务

    promiseKit主流程使用

    上面我们已经包装好了一个promise任务
    其只是一个任务,既不包含调用,也不包含订阅
    下面我们要进行调用和订阅操作
    基础操作符firstly, then, catch

    func loginProtoAndDeal(loginInfo: EduProtoLoginInfo) {
            firstly {
                // 首先会调用此位置的代码
                return self.loginProto(loginInfo: loginInfo)
            }.then { (res: (Bool, String)) in
                // 如果上一个任务中执行了resolver.fulfill,就会执行此代码段
                return self.loginDeal(res: res)
            }.catch { (err)  in
                // self.loginProto(loginInfo: loginInfo)和self.loginDeal(res: res) 包装的两个promise执行了resolver.reject(),就会执行此代码段
                if let resErr = err as? YoungError {
                    YoungLog.error(tag: BusinessFlowTag.login, message: resErr.description)
                }
            }
        }
    
    • fulfill(履行):将结果传递到then分支
    • reject (拒绝):将结果传递到catch分支
      是不是感觉很人性化,一个承诺,要么履行,要么拒绝。

    更多操作符

    always

    从字面意思就可以理解总是都会执行,你可以用在任意位置

    firstly {
                session()
    }.then { data in
      Promise<[String: Any]> { (fulfill, reject) in
       do {
          let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
              fulfill(json as! [String : Any])
           } catch {
               reject(error)
           }
      }
    }.always {
        print("1111")
    }.then { (json) in
        print(json)
    }.always {
        print("always", Thread.current)
    }.catch { (error) in
        print(error)
    }.always {
        print("😁")
     }
    

    when

    when(fulfilled: sessionPromise(), loginPromise()).then { (data, dict) in
        print(data, dict)
    }.catch { error in
        print(error)
    }
    

    你可以同时执行多个Promise,最终会掉到一个then

    race

    字面意思比赛

    race(loginPromise(), loginPromise()).then { winner in
       print(winner)
    }.catch { error in
       print(error)
    }
    

    他同when的区别:

    只有最快的那个会掉到then中
    Promise的泛型必须相同

    then

    firstly {
                sessionPromise()
            }.then(on: DispatchQueue.global()) { data -> Promise<[String: Any]> in
                print("global queue", Thread.current)
                return Promise<[String: Any]> { (fulfill, reject) in
                    do {
                        let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
                            fulfill(json as! [String : Any])
                    } catch {
                            reject(error)
                    }
                }
            }.always {
                print("1111", Thread.current)
            }.then { (json) in
                print(json, Thread.current)
            }.always {
                print("always", Thread.current)
            }.catch { (error) in
                print(error)
            }.always {
                print("😁")
            }
    

    相关文章

      网友评论

        本文标题:swift PromiseKit入门 - promise war

        本文链接:https://www.haomeiwen.com/subject/unoszftx.html