为takeUntil运算符提供哪种方法更好地杀死可观察对象,为什么?

时间:2019-07-05 20:32:39

标签: angular rxjs rxjs-pipeable-operators

我对使用Angular和RxJ的takeUntil运算符取消订阅的常见模式之一有疑问。 在this article中,它位于第三位置。 例如,我们在组件类中有这样的代码:

  private destroy$: Subject<boolean> = new Subject();

  ngOnInit() {
     this.control.
     .pipe(takeUntil(this.destroy$)
     .subscribe(doSmthngFunc); 
  }

  ngOnDestroy() {
    this.destroy$.next(true);
    // Which next line of code is correct?
    // this.destroy$.complete()     // this one?
    // this.destroy$.unsubscribe()  // or this one?
  }

第一行this.destroy $ .next(true)完全清楚。 但是第二个不是。如果我们研究这些方法的实现,就会发现它们具有类似的行为。 complete(): unsubscribe():

据我所知,语义上complete()是可取的,因为我们在组件生命周期中第一次和最后一次调用next(),然后完成此Subject,将其视为Observable并可以调用complete()。这些方法属于观察者,取消订阅属于可观察者,并且我们没有要取消订阅的订阅。 但实际上,这些方法具有类似的代码:

    this.isStopped = true; // both

    this.observers.length = 0; // complete
    this.observers = null;     // unsubscribe

    this.closed = true;        // only unsubscribe

理论上complete()会延迟效果,因为它可能会在每个订阅的观察者上调用complete(),但是我们在destroy $上没有观察者。 因此,问题-哪种方法更可取,更不易出错,为什么?

3 个答案:

答案 0 :(得分:0)

我认为您不需要做更多的事情destroy$.next();destroy$是您在课堂上创建的Subject,它唯一负责的是中止订阅。没有人,但是您的班级允许触摸它(因为它是私人的)

根据该文章,最好执行destroy$.complete()以避免内存泄漏。我认为在其上使用unsubscribe()没有任何意义。如果有人订阅了destroy$,则应将其存储在“订阅”中,并在订阅者“ ngOnDestroy()”方法中退订。但是,由于您使用的是takeUntil,因此无需取消订阅。

答案 1 :(得分:0)

销毁组件是单个事件。

   this.destroy$.next();
   this.destroy$.complete();

确保对象仅发射一次 完成

例如;

    const destroy$ = new Subject();

    destroy$.subscribe(v => console.log("destroyed"));

    destroy$.next();
    destroy$.complete();
    destroy$.next();

    // the above prints "destroyed" only once.

完成技术并不是技术要求,但是如果您不这样做,则依赖于完成而不是发射的业务逻辑将永远无法工作,并且可能会泄漏内存。

例如,以下是RxJ中的内存泄漏。

   destroyed$.subscribe(() => {
       console.log('This might leak memory');
   });

以上内容可能会泄漏内存,因为订阅永远不会结束并且可观察对象永远不会完成。您可以通过添加first()运算符或确保完成主题来修复泄漏。 RxJS不知道主题只会发出一个值,因此您必须告诉它。否则,订户将保持绑定到堆栈框架,并且不会被垃圾回收。因此,尽管垃圾回收器可能在使用了组件之后收集了该组件(如果有任何东西引用了订阅者的堆栈框架),那么该订阅仍然存在。

因此,对您要摧毁的主题打电话给 complete ,这样其他人就不会犯错。

  

this.destroy $ .unsubscribe()

在主题上调用取消订阅可能对创建内部订阅的下游运营商没有影响。例如,switchMap()mergeMap()创建内部订阅。

因此,您不能有效地管理更高级别的订阅。最好取消订阅在调用subscribe()方法时创建的订阅,因为这是操作符链中的最后一个。

答案 2 :(得分:-1)

两个语句都将具有预期的效果。 Afaik没有技术上的理由不使用unsubscribe。语义上-如您所提到-使用complete更有意义。

主题既是可观察的(发送的)又是观察者的(侦听的),并且在此反映了对偶性。 nextcomplete都属于事物的“发送”端。 complete表示“此流将不再发送任何其他值”。 unsubscribe是“监听”界面的一部分,并具有相应的不同含义:“不要将进一步的排放通知我”。

编辑:重新阅读后,我发现您已经在问题中包含了这种区别,因此我的回答可能对您没有多大帮助:(。我确实认为语义很重要本身拥有足够的权利来使用complete over unsubscribe,并且在这种模式下看不到使用其中一个的实际风险。希望仍然有所帮助!