简体   繁体   English

在使用takeUntil模式取消订阅Observable时,是否需要完成主题?

[英]Is completing the Subject necessary when using the takeUntil pattern to unsubscribe from Observables?

To avoid memory leaks in my Angular app i'm using the following well-known pattern to unsubscribe from Observables: 为了避免我的Angular应用程序中的内存泄漏,我使用以下众所周知的模式取消订阅Observables:

unsubscribe = new Subject();

ngOnInit() {
    this.myService.getStuff()
        .pipe(takeUntil(this.unsubscribe))
        .subscribe(result => {
            // processing the result
        });
}

ngOnDestroy() {
    this.unsubscribe.next();
}

This seemingly works fine, but in some examples i've noticed that complete() is also called on the Subject in addition to next() : 这似乎工作正常,但在一些例子中,我注意到除了next()之外,还在Subject上调用了complete() next()

ngOnDestroy() {
    this.unsubscribe.next();
    this.unsubscribe.complete(); // like this
}

Is calling complete() necessary here? 这里需要调用complete()吗? If so, why? 如果是这样,为什么? What are the consequences of not calling complete() in this scenario? 在这种情况下不调用complete()有什么后果?

Let's see why you need to unsubscribe first. 让我们看看为什么你需要先取消订阅。

Very simplified: Observable instance is holding an array of all subscriptions, which means every callback you have in your subscribe will be held in this array. 非常简化:Observable实例持有所有订阅的数组,这意味着您subscribe每个回调都将保存在此数组中。 This is bad news for Component because while it is referred from those functions it cannot be garbage-collected. 这对于Component来说是个坏消息,因为虽然它是从那些函数引用的,但它不能被垃圾收集。 I talk about these functions: 我谈谈这些功能:

ngOnInit() {
    this.myService.getStuff()
        .subscribe(
            result => null, // this function will be stored in Observable
            error => null, // and this
            () => null, // and even this
        );
}

and it is applicable to every subscribe call. 它适用于每个subscribe电话。

Now you add a pipe .pipe(takeUntil(this.unsubscribe)) (or you can eg use my small library that does similar but shorter). 现在你添加一个管道.pipe(takeUntil(this.unsubscribe)) (或者你可以使用我的类似但更短的小型库 )。 In fact, your Observable subscribes to the events of Subject. 实际上,您的Observable订阅了Subject的事件。 And, whenever it emits a value, the Observable returned by this.myService.getStuff() will complete itself. 并且,每当它发出一个值时, this.myService.getStuff()返回的Observable将自行完成。 That means all three functions above will be removed from this Observable's subscriptions array and your component is not referred from there anymore. 这意味着将从此Observable的订阅数组中删除上述所有三个函数,并且不再从那里引用您的组件。

Problem solved. 问题解决了。

All above you need to understand all the why s you have. 以上所有你需要了解你拥有的所有why

Here we finally come to your question 在这里,我们终于提出了你的问题

ngOnDestroy() {
    this.unsubscribe.next();
    this.unsubscribe.complete();
}

where complete is unnecessary, but not harming as well. complete是不必要的,但也不是伤害。 Because the only subscriber to this subject was your Observable from this.myService.getStuff() (or other Observables from the same component). 因为此主题的唯一订阅者是来自this.myService.getStuff() Observable(或来自同一组件的其他Observable)。 That means this Subject will refer to nothing else (the only listener is removed and complete that is supposed to clear all subscriptions is already empty), and as long as only component has reference to the Subject as its property, they both will be collected by garbage collector. 这意味着,这一主题将是指没有别的(唯一的听众被删除, complete是应该清除所有的订阅已经为空),只要唯一组件具有参考主题作为其财产,它们都将被收集垃圾收集器。

This has been discussed previously eg. 这已在前面讨论过,例如。 here Why a 'next' before 'complete' of Angular takeuntil ngUnsubscribe? 为什么在Angular的'完成'之前'下一步'取消订阅?

You basically don't have to call complete() because next() will dispose the chain and takeUntil will unsubscribe from this.unsubscribe for you. 你基本上不必调用complete()因为next()将处理链并且takeUntil将取消订阅this.unsubscribe Only if you had some other logic tied to this.unsubscribe then it might be necessary to call complete() . 只有当你有一些与this.unsubscribe相关的其他逻辑时,才可能需要调用complete()

Anyway, you don't break anything if you do call complete() . 无论如何,如果你调用complete() ,你不会破坏任何东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM