从Angular 2上的异步管道订阅的BehaviorSubject捕获错误时发生无限循环 [英] Infinite loop when catching error from BehaviorSubject subscribed by async pipe on Angular 2

查看:247
本文介绍了从Angular 2上的异步管道订阅的BehaviorSubject捕获错误时发生无限循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个rxjs BehaviorSubject,我使用来自Angular 2的async管道订阅,我有一个catch来处理它引发的最终错误. 问题是,每次遇到错误时,它都会启动一个无限循环,因为我的捕获返回了从BehaviorSubject派生的Observable,并且我认为当我返回catchasync管道将重新订阅到observable.

I have an rxjs BehaviorSubject I subscribe to using an async pipe from Angular 2 and I have a catch to handle eventual errors it throws. Problem is, every time I get an error it starts an infinite loop because my catch returns the Observable derived from the BehaviorSubject and I think the async pipe resubscribes to the observable when I return the catch.

代码大致如下:

ListService -是@Injectable,其中具有BehaviorSubject和具有Observable的属性.

ListService - is a @Injectable where I have the BehaviorSubject and the property with the Observable.

private listSubject: BehaviorSubject<IItem[]>;

public get listObservable() {
    return this.listSubject.asObservable()
}

private error(error: IError) {
    this.listSubject.error(error);
}

ListComponent -是@Component,显示可观察的列表.

ListComponent - is a @Component that shows the list observable.

// Template
<items-view [items]="list | async"></items-view>

// Code
public get list() {
    return this.listService.listObservable
        .catch((error) => {
            this.handleError(error);
            return this.listService.listObservable;
        });
}

如您所见,我的catch返回当前可观察值,因为它必须返回一个可观察值.因此,发生的是,当我发送this.listSubject.error(error)时,代码进入了无限循环调用catch的无限循环,因为像我之前说的那样,我认为BehaviourSubject重新抛出错误是因为async管道当catch返回它时,重新订阅该可观察对象.

As you can see, my catch returns the current observable, as it MUST return an observable. So, what happens is, when I send the this.listSubject.error(error) the code enters an infinite loop calling the catch indefinitely because, like I said before, I think that the BehaviourSubject re-throws the error because the async pipe re-subscribes to the observable when the catch returns it.

我试图返回错误中的上一个缓存数组以返回Observable.of(error.cached),但由于遇到了异步不再订阅BehaviorSubject的问题,我遇到了一系列全新的问题.

I tried to return my previous cached array in the error to return an Observable.of(error.cached), but I got a whole new set of problems because think the async wasn't subscribed to the BehaviorSubject anymore.

就像我之前说过的那样,这是我的真实代码的粗略表示,但是逻辑基本上就是这样.

Like I said before, this is a rough representation of my real code, but the logic is basically that.

我一直在尝试各种不同的方法,但是我无法使这个无限循环停止.

I have been trying various different approaches to this but I couldn't manage to get this infinite loop to stop.

预先感谢您的帮助.

推荐答案

通常,在主题上手动分发错误通常是个坏主意,该主题应该仅弹出数据(例如您的情况下的BehaviorSubject).原因是,当Subject上发生错误时,Subject本质上是 dead ->含义,不再有新数据弹出.这是rxjs的核心概念之一.这是一个小例子:

It is a generally bad idea to manually dispatch an error on a Subject, that is supposed to only eject data (like the BehaviorSubject in your case). The reason is, that when an error occurs on a Subject, the Subject is essentially dead -> meaning, that no new data can be ejected on it any more. This is one of the core-concepts of rxjs. Here is a small example:

let stream$ = new Rx.BehaviorSubject(1);

stream$.subscribe(x => console.log("Logging: " + x), e => console.error("Error: " + e)); // logs 1, 2, Error: ...

stream$.next(2);
stream$.error(new Error("Some error message."));
stream$.next(3); // this will have no effect, because the stream is "dead"
stream$.subscribe(x => console.log("Logging 2: " + x), e => console.error("Error: " + e)); // this will just log the error

对于您的情况,这意味着您进行了一些错误处理,但是只返回了旧的,死的,错误"-主题-换句话说:将错误向下传播. (我不认为handleError()创建一个新的Subject,无论如何这都是可怕的做法.)

For your case this means that you did some error-handling, but then just return the "old, dead, error"-Subject - in other words: propagate the error down the stream. (I'm not assuming that handleError() creates a fresh Subject, which would be an awful practice anyways.)

通常,这意味着.error仅应用于执行定义的操作并具有确定数量的结果,然后完成或引发错误的流,而不能用于要发射数据的Subject在整个应用程序的整个生命周期中.

In general it means that .error should only be used for streams that perform a defined operation and have a defined number of results and then complete or throw an error, but not on Subjects that you want to emit data throughout the complete lifetime of the application.

如何根据您的情况解决此问题:快速&肮脏(真的很脏!)方法是使用两个单独的主题,一个用于数据,另一个用于错误(用.next弹出).

How to solve this in your case: The quick&dirty (really dirty!!) way would be to use two separate Subjects, one for the data and one for errors (eject with .next).

正确的解决方法:将体系结构分为数据生成流和数据存储部分.

The proper fix: Split up your architecture into a data-generation-flow and into a data-store-part.

生命周期如下:

生成流

  1. 某些事件(例如,单击按钮或某些基于时间的事件)
  2. Service.generateOrFetchData().handleErrors()
  3. StoreService.someSubj.next(data)-(步骤3可以是可选的,具体取决于您要如何处理步骤2中的错误)

订阅流程

  1. UI订阅StoreService.someSubj
  2. 每当弹出新数据时,UI都会自动更新,无需进行错误处理


完美的修复方法是使用易于使用的,经过深思熟虑的商店架构,例如


The perfect fix would be to use a ready-to-use thought-through store-architecture like ngrx, however implementing this in an existing project will come with major refactoring requirements.

这篇关于从Angular 2上的异步管道订阅的BehaviorSubject捕获错误时发生无限循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆