swift PromiseKit入门 - promise war
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("😁")
}