响应式设计:抛出与发布错误
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 的代码都需要准备好处理。
下面的代码示例有 (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 的代码都需要准备好处理。