javascript - 如果 Observable 完成了,我是否需要取消订阅 Observable?
问题描述
假设我有一个Observable
(热门,未完成),并且我订阅了它。通常,当我完成后,Subscription
我必须取消订阅以防止内存泄漏。
let subject$ = new Subject();
const sub = subject$.subscribe(...);
...
// Need to call sub.unsubscribe() when we are finished
sub.unsubscribe();
sub = null;
但是,如果不仅完成了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?
我的逻辑告诉我我没有,因为 theSubject
和 theSubscription
现在都有资格进行垃圾收集,并且将被销毁,即使它们相互引用。还是有一些我不知道的隐藏参考?
不要担心 using 或其他机制之间的unsubscribe
区别takeUntil
。
解决方案
如果let subject$ = new Subject();
清除对Subject
和的引用Subscription
就足够了,之后所有内容都将被垃圾收集。
当您订阅对象时,内存泄漏的风险变得真实,并且您在清除对象上的所有引用之前Subject
没有取消订阅。Subject
在这种情况下,整个对象将保持活动状态并且不会被垃圾回收。
让我们看这个例子:
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;
在这个例子中,当清除所有对 的引用时bigObject
,subject
仍然有一个对回调的引用,该x => this.result = x
回调有一个对 的引用bigObject
,使其整体无法回收。
通过取消订阅或清除subject
,这将破坏保持bigObject
活动的引用链,并且它将有资格进行垃圾收集。
要自己观察行为,您可以在控制台中复制此文件https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.3/rxjs.umd.min.js的内容,然后复制粘贴示例代码。您会注意到任务管理器中的内存增加。在开发人员工具的内存选项卡中创建堆转储时,您可以通过BigClass
在搜索字段中键入来找到这 4 个对象。
之后,subject = null;
在控制台中输入,然后创建一个新的堆转储。您会注意到 4 个对象已消失。
总而言之,只要 anObservable
被销毁,就没有真正的内存泄漏风险,因为所有订阅也将被销毁。有风险Observables
的是那些永久的(例如:附加到全局 DOM 事件fromEvent
),并且回调引用需要销毁的对象。
推荐阅读
- javascript - 每 60 秒运行一次函数
- python - Python pandas read csv 不断改变我的日期时间格式,当我专门将它指定为字符串或对象格式时仍然会发生
- compiler-errors - 如何将 Swift UI 代码中的表达式分解为不同的子表达式?
- json - 如何在 Dart 中使用 json_annotation 将 Uint8List 序列化为 json?
- actionscript-3 - Jetbrains IDEA 编译 Flash 项目慢时如何更快?
- java - 在 Spring Boot 中使用 JPA 保存时,有没有办法获得“刷新”保存的实体?
- r - R,ggplot2:在不更改其他网格线的情况下向轴添加特定的刻度+标签
- django - 'str' 对象在 django 中没有属性 'as_view'
- list - 在 Prolog 中递归创建后代列表
- c# - 解析来自 REST 请求的响应时出现错误编码