简体   繁体   English

如果 Observable 已完成,我是否需要取消订阅 Observable?

[英]Do I need to unsubscribe from an Observable if the Observable is finished with?

Let us say I have an Observable (hot, doesn't complete), and I subscribe to it.假设我有一个Observable (热的,未完成),并且我订阅了它。 Ordinarily when I am finished with the Subscription I have to unsubscribe it to prevent memory leaks.通常,当我完成Subscription我必须取消订阅以防止内存泄漏。

let subject$ = new Subject();

const sub = subject$.subscribe(...);
...
// Need to call sub.unsubscribe() when we are finished
sub.unsubscribe();
sub = null;

But if instead of just being finished with the Subscription I am also finished with the Observable ( Subject ) and I remove all reference to both, do I need to call unsubscribe method?但是,如果不是刚刚完成Subscription我也完成了Observable ( Subject ) 并且我删除了对两者的所有引用,我是否需要调用unsubscribe方法?

let subject$ = new Subject();

const sub = subject$.subscribe(...);
...
sub = null;
subject$=null;
// Assume I have no other references to these
// Do I need to call sub.unsubscribe() in this case?

My logic is telling my I don't because both the Subject and the Subscription are now eligible for garbage collection, and will be destroyed, even though they reference each other.我的逻辑告诉我我没有,因为SubjectSubscription现在都有资格进行垃圾收集,并且会被销毁,即使它们相互引用。 Or is there some hidden reference I don't know about?还是有一些我不知道的隐藏参考?

Don't worry about the difference between using unsubscribe , takeUntil or other mechanisms.不要担心使用unsubscribetakeUntil或其他机制之间的区别。

In the case of a let subject$ = new Subject();let subject$ = new Subject(); clearing the references to the Subject and the Subscription will be enough, everything will be garbage collected after that.清除对SubjectSubscription的引用就足够了,之后所有内容都将被垃圾收集。

The risk of a memory leak gets real when you are subscribing to the Subject in an object, and you don't unsubscribe from the Subject before clearing all the references on the object.当您订阅对象中的Subject在清除对象上的所有引用之前不取消订阅Subject时,内存泄漏的风险就会变得真实。 In that case, the whole object will remain active and won't be garbage collectable.在这种情况下,整个对象将保持活动状态并且不会被垃圾回收。

Let's take this example:让我们以这个例子为例:

class BigClass {
    constructor(observable) {
        this.bigArray = new Array(9999999).fill(0);
        observable.subscribe(x => this.result = x);
    }
    //...
}

let subject = new rxjs.Subject();
let bigObject = new BigClass(subject);
let bigObject1 = new BigClass(subject);
let bigObject2 = new BigClass(subject);
let bigObject3 = new BigClass(subject);

bigObject = null;
bigObject1 = null;
bigObject2 = null;
bigObject3 = null;

In this example, when clearing all the references on bigObject , the subject still has a reference on the x => this.result = x callback which has a reference on bigObject , making it uncollectable as a whole.在这个例子中,当清除bigObject上的所有引用时, subject仍然在x => this.result = x回调上有一个引用,它在bigObject上有一个引用,使它作为一个整体无法收集。

Either by unsubscribing, or clearing the subject , this will break the references chain that keeps bigObject alive, and it will be eligible for garbage collection.通过取消订阅或清除subject ,这将破坏保持bigObject存活的引用链,并且将有资格进行垃圾收集。

To observe the behavior by yourself, you can copy the content of this file https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.3/rxjs.umd.min.js in your console, then copy paste the example code.要自己观察行为,您可以在控制台中复制此文件https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.3/rxjs.umd.min.js的内容,然后复制粘贴示例代码。 You will notice a memory increase in the task manager.您会注意到任务管理器中的内存增加。 When creating a heap dump in the Memory tab in the developer tools, you'll be able to find the 4 objects by typing BigClass in the search field.在开发人员工具的“内存”选项卡中创建堆转储时,您可以通过在搜索字段中键入BigClass来找到 4 个对象。

After that, type subject = null;之后,输入subject = null; in the console, then create a new heap dump.在控制台中,然后创建一个新的堆转储。 You'll notice that the 4 objects have disappeared.您会注意到 4 个对象已经消失。

As a conclusion, as long as an Observable is destroyed, these is no real risk of a memory leak because all of the subscriptions will also be destroyed.总而言之,只要Observable被销毁,就没有真正的内存泄漏风险,因为所有订阅也将被销毁。 The risky Observables are those who are permanent (eg: attached to a global DOM event with fromEvent ), and with callbacks referring to objects that need to be destroyed.有风险的Observables是永久性的(例如:通过fromEvent附加到全局 DOM 事件),并且带有指向需要销毁的对象的回调。

No, you don't need to不,你不需要

For memory usage there's no difference.对于内存使用,没有区别。

When you call sub.unsubscribe();当你调用sub.unsubscribe(); the only thing that RXJS does is to set the observers to null , here you can see the original RXJS unsubscribe code : RXJS 所做的唯一一件事就是将观察者设置为null在这里您可以看到原始的 RXJS 取消订阅代码

  unsubscribe() {
    this.isStopped = true;
    this.closed = true;
    this.observers = null!;
  }

The flags are used only for further validations.这些标志仅用于进一步验证。

However i would recomend you to stick with the unsubscribe way, that would be because you never know what RXJS will add in future versions.但是我建议你坚持unsubscribe方式,那是因为你永远不知道RXJS会在未来的版本中添加什么。 For example there's the posibility that they add a new feature, something like this:例如,他们有可能添加新功能,如下所示:

  unsubscribe() {
    this.isStopped = true;
    this.closed = true;
    this.observers = null!;
    if (this.coolNewFeature) {
        this.coolNewFeature.unsubscribe()
    }
  }

In that scenario you'r approach of just doing subject = null;在那种情况下,您只需执行subject = null; will cause memory-leaks.会导致内存泄漏。

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

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