从Angular 2上的异步管道订阅的BehaviorSubject中捕获错误时的无限循环

时间:2016-11-21 08:55:54

标签: angular typescript infinite-loop rxjs observable

我有一个rxjs BehaviorSubject我订阅了使用Angular 2中的async管道,我有一个catch来处理它抛出的最终错误。 问题是,每次我收到一个错误它都会启动一个无限循环,因为我的catch返回从BehaviorSubject派生的Observable,我认为async管道在我返回{{1}时重新订阅了observable }。

代码看起来大致如下:

ListService - 是catch,其中包含BehaviorSubject和@Injectable的属性。

Observable

ListComponent - 是private listSubject: BehaviorSubject<IItem[]>; public get listObservable() { return this.listSubject.asObservable() } private error(error: IError) { this.listSubject.error(error); } ,显示可观察的列表。

@Component

正如你所看到的,我的catch返回当前的observable,因为它必须返回一个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; }); } 时,代码进入一个无限循环,无限期地调用this.listSubject.error(error)因为,就像我之前说过的那样,我认为catch会重新抛出错误因为BehaviourSubject管道在async返回时重新订阅了observable。

我试图在错误中返回我之前的缓存数组以返回catch,但是我遇到了一系列新问题,因为认为async不再订阅Observable.of(error.cached)

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

我一直在尝试各种不同的方法,但我无法设法让这个无限循环停止。

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:3)

在主题上手动调度错误通常是个坏主意,该错误应该只会弹出数据(例如您的BehaviorSubject)。原因是,当Subject发生错误时,Subject基本上 - &gt;这意味着,不再有新的数据可以被弹出。这是rxjs的核心概念之一。这是一个小例子:

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

对于你的情况,这意味着你做了一些错误处理,但只是返回&#34;旧的,死的,错误&#34; -Subject-换句话说:沿着流传播错误。 (我并不是假设handleError()创建了一个新的Subject,无论如何这都是一种可怕的做法。)

一般来说,这意味着.error只应用于执行已定义操作且具有已定义数量的结果然后完成或抛出错误的流,但不应用于Subject s想要在应用程序的整个生命周期内发出数据。

如何在你的情况下解决这个问题:快速和肮脏(真的很脏!!)的方式是使用两个单独的主题,一个用于数据,一个用于错误(用.next弹出)。

正确修复:将您的体系结构拆分为数据生成流和数据存储部分。

生命周期看起来像这样:

生成流程

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

    1. UI订阅StoreService.someSubj
    2. 只要弹出新数据,UI就会自动更新,无需错误处理
    3. 完美修复程序将使用即时使用的思维导致商店架构,如ngrx,但在现有项目中实现此功能将带来重大的重构要求。