PromiseKit 如何实现 Retry?
in 技术 with 0 comment

PromiseKit 如何实现 Retry?

in 技术 with 0 comment

如果你使用 PromiseKit 的时候,总是想得到一个 Guarantee 的结果(非 error)。目前 Retry 是个很好的解决办法。

目前

PromiseKit 并没有实现这个功能。根据 issues 里的说法,有人认为其是反模式的行为。就像其 PromiseKit 没有 UIButton 的扩展是一样的道理(原文):

Be careful with Promises and delegate systems, as they are not always compatible. 
Promises complete once, whereas most delegate systems may notify their delegate many times. 
This is why, for example, there is no PromiseKit extension for a UIButton.

但是

假如你的接口报错,假如定位失败,假如授权失败等等。想重试却是个非常普遍的场景。

实现

/*
1. 该方法并不需要作为 Promise 的扩展实现,直接全局方法定义即可。参考 firstly 方法的实现;
2. 如果返回 Error,则会继续重试循环。否则会退出重试循环;
3. times 表示重试次数,times = 0 表示无限次。cooldown 表示延迟秒数, cooldown = 0 表示无延迟。
*/
@discardableResult
func retry<T>(times: Int = 0, cooldown: TimeInterval = 0, body: @escaping () -> Promise<T>) -> Promise<T> {
  var retryCounter = 0
  func attempt() -> Promise<T> {
    return body().recover(policy: CatchPolicy.allErrorsExceptCancellation) { error -> Promise<T> in
      retryCounter += 1
      guard times == 0 || retryCounter <= times else {
        throw error
      }
        return after(seconds: cooldown).then(attempt)
    }
  }
  return attempt()
}

使用示例:

//check() 必须执行成功,才可以继续执行 config()
retry{ () -> Promise<Void> in
    return firstly{() -> Promise<RequestEnum> in
        return self.check()
    }.then{(result) -> Promise<Void> in
        switch result{
        case .shouldConfig:
            return self.config()
        case .notShouldConfig:
            return Promise()
        case let .error(message):
            return self.alertView(message: message).then {
                //在 Alert 弹框里面,由用户点击确定后再重试
                return Promise(error: PMKError.returnedSelf)
            }
        }
    }
}
Responses