【问题标题】:PromiseKit 6.0 passing catched errors to callerPromiseKit 6.0 将捕获的错误传递给调用者
【发布时间】:2018-09-23 14:03:06
【问题描述】:

根据迁移指南 PromiseKit 6.x 更改了他关于 catch 块的策略。在 PMK 4 中,catch 返回了它所附加的承诺。现在catch 是一个链终止符。我理解为什么要进行这些更改,但是...

在我的代码库(与 PK4 连接)中,我从 catch 返回的承诺中获得了一些优势。

func loginAndSync(withServerAddress address: String, port: String) -> Promise<()> {
    synchronizationService.stopAllRunningSingleSynchronizations()

    return
        authorizationService.save(serverAddress: address, andPort: port)
            .then {
                self.synchronizationService.startSingleFullSynchronization()
            }
            .then {
                self.authorizationService.markAsServerSynced()
            }
            .catch { error in
                log.error(error)
                _ = self.authorizationService.markAsServerUnsynced()
            }
}

在这个函数中,我做了一些在某些情况下可能失败的逻辑。如果出现错误catch 块应该做一些逻辑,但我还想向loginAndSync 函数的调用者发送这个承诺的结果(履行或拒绝)。上面的函数可以被 ViewController 调用,在 ViewController 中我想显示错误或成功对话框。

这就是我需要一个 Promise 链的两个 catches 的原因。一种用于authorizationService,一种用于UI

PromiseKit6 中是否有任何解决方法来实现这一点?

编辑

我找到了两种解决方案(变通方法)。我创建了两个答案来将它们分开。未来的读者可以决定哪一个更好或提供新的。

【问题讨论】:

    标签: ios swift promise promisekit


    【解决方案1】:

    我已将我的 Promise 链包裹在另一个 Promise 中:

    func loginAndSync(withServerAddress address: String, port: String) -> Promise<()> {
        synchronizationService.stopAllRunningSingleSynchronizations()
    
        return Promise { seal in
            authorizationService.save(serverAddress: address, andPort: port)
                .then {
                    self.synchronizationService.startSingleFullSynchronization()
                }
                .then {
                    self.authorizationService.markAsServerSynced()
                }
                .done {
                    self.coordinatorDelegate?.handleLoginServerSuccess()
                    seal.fulfill(())
                }
                .catch {
                    log.error($0)
                    _ = self.authorizationService.markAsServerUnsynced()
                    seal.reject($0)
                }
        }
    }
    

    它应该可以工作,但我不知道这是一个好方法。

    【讨论】:

    • 我最近遇到了同样的问题,并通过将承诺包装在另一个承诺中来解决它。这个问题有更好的解决方案吗?
    【解决方案2】:

    我发现 (IMO) 更好的解决方法。 PromiseKit6 引入了非常方便的方法tap。我已经尝试用它来解决我的问题。

    func loginAndSync(withServerAddress address: String, port: String) -> Promise<()> {
        synchronizationService.stopAllRunningSingleSynchronizations()
    
        return authorizationService.save(serverAddress: address, andPort: port)
            .then {
                self.synchronizationService.startSingleFullSynchronization()
            }
            .then {
                self.authorizationService.markAsServerSynced()
            }
            .tap { result in
                switch result {
                case .rejected(let error):
                    log.error(error)
                    _ = self.authorizationService.markAsServerUnsynced()
                default: break
                }
            }
            .done {
                self.coordinatorDelegate?.handleLoginServerSuccess()
            }
    }
    

    对于文档:

    tap 为您提供链的当前结果,如果链成功或失败,则调用它

    所以我可以为终止链的 Promise 的当前状态提供自定义错误处理。 Promise 可以发送给发件人,在那里我可以做另一个tap 或通过catch 终止链。

    【讨论】:

    • 您也可以使用“recover”而不是“tap”。然后您不必每次都打开结果,因为您会收到错误本身。因此,您可以通过执行一些逻辑来响应错误,然后返回错误(对于后续的恢复块或其他人的 catch 块)。在多个层次上“响应错误”的任务使用恢复功能更强大,因为您可以做更多的事情,例如返回承诺子分支的根?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多