响应式设计:抛出与发布错误

Reactive design: throw vs. publish error

下面的代码示例有 (Rx)Swift 的味道,但这个问题对任何具有反应特性和抛出能力的语言都是通用的。

考虑一个 return 是可观察序列的函数,但它会在创建序列之前进行一些健全性检查。检查失败意味着序列不能产生值。

func yieldFoos() -> Observable<Foo> {
  guard isValid(internalFoo) else {
    // throw or return one shot observable?
  }
  return createValidObservable(from: internalFoo)
}

在状态有效性检查失败的情况下,函数是否应该抛出或 return 一次性观察到,这只会产生错误?我的程序员的胆量得出了这些利弊:

抛出在逻辑上感觉更清晰(它是阻止可观察创建的失败),但导致调用代码繁琐 - catch 块,不同执行范围的多个错误处理点。

一次可观察到的调用代码更短更清晰,但不知何故感觉不对。为了简洁起见,observable 被迫成为非顺序错误状态的载体。

有人有强烈的意见值得关注吗?或者另一个被忽视的优雅解决方案?

你的函数应该是这样的:

func yieldFoos() -> Observable<Foo> {
    Observable.create { observer in 

        guard isValid(internalFoo) else {
            observer.onError(yourError)
        }

        let subscription =  
            createValidObservable(from: internalFoo)
                .subscribe(onNext: { foo in
                    observer.onNext(foo)
                    observer.onCompleted()
                })
        return Disposables.create {
            // your dispose
            subscription.dispose()
        }
    }

}

然后,当您调用它时:

yieldFoos()
    .subscribe(
     onNext: { foo in
         // your code with foo
     },
     onError: { error in
        // manage errors
     })
    .addDisposableTo(disposeBag)

我想知道您是否认为 Observable 发出错误是错误的。这是它工作的一部分。

当你想到它时,你的 createValidObservable(from:) 函数可能会发出一个错误,尽管它被传递给一个有效的 internalFoo 所以调用 yieldFoos() 的代码无论如何都必须准备好处理发出的错误。您不妨将所有错误处理代码汇总在一起。我会更进一步,让你的创建函数能够通过发出错误并取消这个 yieldFoos 函数来处理无效的 foos 本身。

现在,如果你想 yieldFoos() 到 return 一个 Driver 而不是一个 observable, 然后 你必须通过抛出或前提条件(因为驱动程序不会发出错误。)

func yieldFoos() -> Observable<Foo> {
    guard isValid(internalFoo) else {
        return Observable.error(myError)
    }
    return createValidObservable(from: internalFoo)
}

我认为你需要克服这样一种感觉,即拥有一个立即 return 出现错误的 Observable 是错误的。对于 Observable 来说,这是一件完全有效的事情,所有使用该 Observable 的代码都需要准备好处理。