ngOnDestroy 中的 RxJS "unsubsribe" 方法处理资源的速度不够快
RxJS "unsubsribe" method in ngOnDestroy does not disposes resources quickly enough
我正在调查一个问题,该问题似乎是由于“订阅”class 的“取消订阅”方法似乎没有足够快地处理资源而导致内存泄漏.
这是我的场景:
我有 2 个组件 - LandingPageComponent (LPC) 和 WebPlayerComponent (WPC)。 LPC 是用户访问站点时看到的第一个页面。在该页面上,他们有一个 link 将他们带到第二页或 WPC(传递参数,例如“Operator Benchmarking”) 用户返回到上一页通过单击浏览器的后退按钮。这会触发 WPC 的 ngOnDestroy 方法,该方法处理订阅(参见下面的代码)。
WebPlayerComponent
export class WebPlayerComponent implements OnInit, OnDestroy {
@Input() workbookId: string;
@Input() workbookPage: string | number;
private _workbooks: Workbook[];
private _filters: Filter[];
private _subscriptions: { [key: string]: Subscription } = {};
ngOnInit() {
this._subscriptions["combined"] = combineLatest(
this.workbookService.workbooks$,
this.filterService.filters$,
this.libraryService.userFolderInitialised$
).subscribe(([workbooks, filters, userFolderInitialised]) => {
this._workbooks = workbooks;
this._filters = filters;
this._subscriptions["webPlayerServiceSubscription"] = this.webPlayerService.openWorkbook(workbook.libraryPath, parameterString).subscribe(
(webPlayer) => {
console.log("_subscriptions before 'openWorkbook call'");
Object.keys(this._subscriptions).map((key) => {
console.log(key);
});
console.log("Openning document page: " + this.workbookPage);
webPlayer.openDocument("spotfire-container", this.workbookPage);
});
});
}
ngOnDestroy() {
Object.keys(this._subscriptions).map((key) => {
this._subscriptions[key].unsubscribe();
console.log("---Unsubscribed " + key + "---");
});
}
}
如果用户单击浏览器的后退按钮并足够快地单击“Link”(在我的示例中少于 5 秒),问题就会开始出现。应该处理的订阅没有并且仍然处于活动状态。我可以通过查看控制台的输出来确认:
在上图中,您可以看到在 LandingPageComponent 再次点击“Link”后,我们看到了 2 组调用(绿色数字(1 ) & (2)),我们还看到了“打开文档页面:” 3次
如果我在再次单击 link 之前等待 5 秒,输出应该是这样的
我不确定为什么我的订阅资源处理得不够快(至少我认为这是问题所在)。
注意:我正在使用 RxJS 6.4.0 和 Angular 8.1.3
您可以像这样使用switchMap
:
ngOnInit() {
this._subscriptions["combined"] = combineLatest(
this.workbookService.workbooks$,
this.filterService.filters$,
this.libraryService.userFolderInitialised$
)
.pipe(
switchMap(([workbooks, filters, userFolderInitialised]) => {
this._workbooks = workbooks;
this._filters = filters;
return this.webPlayerService.openWorkbook(workbook.libraryPath, parameterString)
})
)
.subscribe((webPlayer) => {
webPlayer.openDocument("spotfire-container", this.workbookPage);
});
}
因此您将可观察值从 combineLatest
更改为 openWorkbook
我正在调查一个问题,该问题似乎是由于“订阅”class 的“取消订阅”方法似乎没有足够快地处理资源而导致内存泄漏.
这是我的场景:
我有 2 个组件 - LandingPageComponent (LPC) 和 WebPlayerComponent (WPC)。 LPC 是用户访问站点时看到的第一个页面。在该页面上,他们有一个 link 将他们带到第二页或 WPC(传递参数,例如“Operator Benchmarking”) 用户返回到上一页通过单击浏览器的后退按钮。这会触发 WPC 的 ngOnDestroy 方法,该方法处理订阅(参见下面的代码)。
WebPlayerComponent
export class WebPlayerComponent implements OnInit, OnDestroy {
@Input() workbookId: string;
@Input() workbookPage: string | number;
private _workbooks: Workbook[];
private _filters: Filter[];
private _subscriptions: { [key: string]: Subscription } = {};
ngOnInit() {
this._subscriptions["combined"] = combineLatest(
this.workbookService.workbooks$,
this.filterService.filters$,
this.libraryService.userFolderInitialised$
).subscribe(([workbooks, filters, userFolderInitialised]) => {
this._workbooks = workbooks;
this._filters = filters;
this._subscriptions["webPlayerServiceSubscription"] = this.webPlayerService.openWorkbook(workbook.libraryPath, parameterString).subscribe(
(webPlayer) => {
console.log("_subscriptions before 'openWorkbook call'");
Object.keys(this._subscriptions).map((key) => {
console.log(key);
});
console.log("Openning document page: " + this.workbookPage);
webPlayer.openDocument("spotfire-container", this.workbookPage);
});
});
}
ngOnDestroy() {
Object.keys(this._subscriptions).map((key) => {
this._subscriptions[key].unsubscribe();
console.log("---Unsubscribed " + key + "---");
});
}
}
如果用户单击浏览器的后退按钮并足够快地单击“Link”(在我的示例中少于 5 秒),问题就会开始出现。应该处理的订阅没有并且仍然处于活动状态。我可以通过查看控制台的输出来确认:
在上图中,您可以看到在 LandingPageComponent 再次点击“Link”后,我们看到了 2 组调用(绿色数字(1 ) & (2)),我们还看到了“打开文档页面:” 3次
如果我在再次单击 link 之前等待 5 秒,输出应该是这样的
我不确定为什么我的订阅资源处理得不够快(至少我认为这是问题所在)。
注意:我正在使用 RxJS 6.4.0 和 Angular 8.1.3
您可以像这样使用switchMap
:
ngOnInit() {
this._subscriptions["combined"] = combineLatest(
this.workbookService.workbooks$,
this.filterService.filters$,
this.libraryService.userFolderInitialised$
)
.pipe(
switchMap(([workbooks, filters, userFolderInitialised]) => {
this._workbooks = workbooks;
this._filters = filters;
return this.webPlayerService.openWorkbook(workbook.libraryPath, parameterString)
})
)
.subscribe((webPlayer) => {
webPlayer.openDocument("spotfire-container", this.workbookPage);
});
}
因此您将可观察值从 combineLatest
更改为 openWorkbook