反应式设计:抛出与发布错误
Posted
技术标签:
【中文标题】反应式设计:抛出与发布错误【英文标题】:Reactive design: throw vs. publish error 【发布时间】:2017-05-23 11:48:52 【问题描述】:下面的代码示例有 (Rx)Swift 的味道,但这个问题对于任何具有反应特性和抛出能力的语言都是通用的。
考虑一个返回可观察序列的函数,但它会在创建序列之前进行一些完整性检查。检查失败意味着序列不能产生值。
func yieldFoos() -> Observable<Foo>
guard isValid(internalFoo) else
// throw or return one shot observable?
return createValidObservable(from: internalFoo)
在状态有效性检查失败的情况下,该函数应该抛出还是返回一个可观察的镜头,这将只产生一个错误?我的编码员的胆量想出了这些优点和缺点:
Throwing 在逻辑上感觉更干净(这是一个阻止 observable 创建的失败),但会导致繁琐的调用代码 - catch 块、不同执行范围内的多个错误处理点。
One shot observable 导致调用代码更短更清晰,但不知何故感觉不对。为了简洁起见,observable 被强制作为非顺序错误状态的载体。
有人有强烈的意见值得追随吗?还是另一种被忽视的优雅解决方案?
【问题讨论】:
【参考方案1】:我想知道您是否认为 Observable 发出错误是错误的。这是它工作的一部分。
当您考虑它时,您的 createValidObservable(from:)
函数可能会发出错误,尽管传递给了一个有效的 internalFoo,因此调用 yieldFoos()
的代码无论如何都必须准备好处理发出的错误。您不妨将所有错误处理代码放在一起。我会更进一步,让您的 create 函数能够通过发出错误并取消此 yieldFoos 函数来处理无效的 foos 本身。
现在,如果您希望 yieldFoos()
返回 Driver
而不是 observable,那么您必须通过抛出或前置条件来处理错误(因为驱动程序不会发出错误。 )
func yieldFoos() -> Observable<Foo>
guard isValid(internalFoo) else
return Observable.error(myError)
return createValidObservable(from: internalFoo)
我认为你需要克服你的感觉,即拥有一个立即返回错误的 Observable 是错误的。这对于 Observable 来说是一件非常有效的事情,并且所有使用该 Observable 的代码都需要准备好处理。
【讨论】:
Observable 发出错误并没有错。我只是觉得这样的错误应该是“可观察的”(无法继续序列),而不是首先创建可观察的。序列失败是正常的,创建失败是异常的不一致,因此抛出似乎是合适的。但是单发Observable.error
运营商的存在暗示我可能只是想太多了。
如果你的 create 函数被传递了一个无效的 internalFoo,它将无法继续这个序列...... :-) 将 Observable 错误视为他们的 throw 版本可能会有所帮助,或者考虑它作为异步事件的抛出。它的工作原理就像一个投掷,它通过管道传播,直到它被处理......
所以你会这样说 - 在反应式代码中,一般来说抛出的用例更少吗?我认为关键的反应性概念之一是一切都可以逐渐异步甚至懒惰,但您的转换代码不应该关心。而投掷本质上是同步的......
不,这不太对……我是说 Rx 的 onError 事件类似于 throw。例如,如果您在 flatMapLatest
或任何其他 Rx 运算符中抛出,它将自动转换为 onError
事件。异常和错误事件是表示相同抽象的两种不同方式。是的,抛出是同步的,但错误事件也是同步的,因为它们会立即关闭可观察的链。
@PavelZdenek 我看到了您澄清的关于创建失败与序列失败的区别。您如何看待通过抛出创建 Observable 的错误和发出错误(分别)来区分它们?即yieldFoos() throws -> Observable<Foo>
,其中如果创建observable失败,则会抛出错误。但是,如果可观察序列中有错误,则它会以 onError 事件终止。这样就可以将 observable 的错误与序列错误区分开来。【参考方案2】:
你的函数应该是这样的:
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)
【讨论】:
我知道如何构造和使用 observables,谢谢。我在问是否应该抛出异常故障或按顺序排列。你似乎喜欢序列,但没有推理。以上是关于反应式设计:抛出与发布错误的主要内容,如果未能解决你的问题,请参考以下文章
Cloudinary openUploadWidget 在我的反应应用程序中抛出错误
反应:npm start 工作,npm run build 抛出 ELIFECYCLE 错误(errno 1)
为啥 npm start 会抛出 events.js:187 throw er; // 我的反应项目中未处理的“错误”事件?