代码之家  ›  专栏  ›  技术社区  ›  Alex Stone

如何防止序列被释放(抛出错误)?

  •  0
  • Alex Stone  · 技术社区  · 6 年前

    let inputRelay = PublishRelay<Int>()
    let outputRelay = PublishRelay<Result<Int>>()
    
    inputRelay
    .map{ /*may throw multiple errors*/}
    .flatmap{ /*may throw error*/ }
    .map{}
    .filter{}
    .map{ _ -> Result<Int> in ...}
    .catchError{}
    .bind(to: outputRelay)
    

    我以为 catchError 只需捕获错误,允许我将其转换为失败结果,但阻止序列被释放。但是,我看到第一次捕捉到错误时,整个序列都被释放,不再发生任何事件。

    如果没有这种行为,我将得到一个到处都是的结果,并且必须多次分支我的序列来指导 Result.failure(Error) retry(n) 不是选项:

    let firstOp = inputRelay
    .map{ /*may throw multiple errors*/}
    .share()
    
    //--Handle first error results--
    firstOp
    .filter{/*errorResults only*/}
    .bind(to: outputRelay)
    
    let secondOp = firstOp
    .flatmap{ /*may throw error*/ }
    .share()
    
    //--Handle second error results--
    secondOp
    .filter{/*errorResults only*/}
    .bind(to: outputRelay)
    
    secondOp
    .map{}
    .filter{}
    .map{ _ -> Result<Int> in ...}
    .catchError{}
    .bind(to: outputRelay)
    

    ^这是非常糟糕的,因为大约有7个地方可以抛出错误,而我不能每次都对序列进行分支。

    RxSwift运算符如何捕捉所有错误并在最后发出失败结果,但不在第一个错误时处理整个序列?

    2 回复  |  直到 6 年前
        1
  •  12
  •   Shai Mishali    6 年前

    首先想到的诀窍是使用 materialize . 这会改变 Observable<T> Observable<Event<T>> ,所以一个错误就是 .next(.error(Error))

    物化 在特定的地方。这是必需的,因为物化序列仍然可以完成,这将导致在常规链的情况下终止,但不会终止平面映射链(as complete==成功完成,在平面映射内)。

    inputRelay
        .flatMapLatest { val in
            return Observable.just(val)
                .map { value -> Int in
                    if value == 1 { throw SomeError.randomError }
                    return value + value
                }
                .flatMap { value in
                    return Observable<String>.just("hey\(value)")
                }
                .materialize()
        }
        .debug("k")
        .subscribe()
    
        inputRelay.accept(1)
        inputRelay.accept(2)
        inputRelay.accept(3)
        inputRelay.accept(4)
    

    这将为输出以下内容 k

    k -> subscribed
    k -> Event next(error(randomError))
    k -> Event next(next(hey4))
    k -> Event next(completed)
    k -> Event next(next(hey6))
    k -> Event next(completed)
    k -> Event next(next(hey8))
    k -> Event next(completed)
    

    下一个要做的就是过滤“所有事件”。

    如果你有 RxSwiftExt errors() elements() 操作员:

    stream.elements()
        .debug("elements")
        .subscribe()
    
    stream.errors()
        .debug("errors")
        .subscribe()
    

    errors -> Event next(randomError)
    elements -> Event next(hey4)
    elements -> Event next(hey6)
    elements -> Event next(hey8)
    

    使用这种策略时,不要忘记添加 share() 在你的 flatMap

    您可以在此处阅读有关在这种情况下使用共享的更多信息: http://adamborek.com/how-to-handle-errors-in-rxswift/

    希望这有帮助!

        2
  •  1
  •   Daniel T.    6 年前

    有一些反应库允许您指定 Never 作为错误类型(意味着根本无法发出错误),在rxcooa中,您可以使用Driver(它不能出错),但您仍然可以使用整个结果舞蹈。”Monads在我的Monads中!“。

    为了正确地处理它,你需要一套 Monad transformers