Angular RxJS“;“取消订阅”;Ngondestory中的方法没有足够快地处理资源

Angular RxJS“;“取消订阅”;Ngondestory中的方法没有足够快地处理资源,angular,rxjs,rxjs6,rxjs-observables,Angular,Rxjs,Rxjs6,Rxjs Observables,我正在调查一个问题,这似乎是由于“Subscription”类的“unsubscribe”方法处理资源的速度不够快,导致内存泄漏 以下是我的设想: 我有两个组件-登陆页面组件(LPC)和网络播放器组件(WPC)。LPC是用户访问站点时看到的第一个页面。在该页面上,他们有一个链接,将他们带到第二个页面或WPC(传递参数,例如“操作员基准测试”),用户通过单击浏览器的“后退”按钮返回到上一个页面。这将触发WPC的Ngondestory方法,该方法处理订阅(见下面的代码) WebPlayerComp

我正在调查一个问题,这似乎是由于“Subscription”类的“unsubscribe”方法处理资源的速度不够快,导致内存泄漏

以下是我的设想:

我有两个组件-登陆页面组件(LPC)和网络播放器组件(WPC)。LPC是用户访问站点时看到的第一个页面。在该页面上,他们有一个链接,将他们带到第二个页面或WPC(传递参数,例如“操作员基准测试”),用户通过单击浏览器的“后退”按钮返回到上一个页面。这将触发WPC的Ngondestory方法,该方法处理订阅(见下面的代码)

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 + "---");
        });
    }
}
如果用户单击浏览器的“后退”按钮并足够快地单击“链接”(在我的示例中,这是少于5秒的时间),问题就会开始出现。假定要处理的订阅不是并且仍然处于活动状态。我可以通过查看控制台的输出来确认:

在上图中,您可以看到,在从登陆页面组件再次点击“链接”后,我们看到两组呼叫(绿色号码(1)和(2)),我们还看到“打开文档页面:”3次

如果我在再次单击链接之前等待5秒钟,输出应该是这样的

我不确定为什么我的订阅资源没有得到足够快的处理(至少我认为这就是问题所在)


注意:我使用的是RxJS 6.4.0Angular 8.1.3您可以使用
开关映射
如下:

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);
     });
    }

因此,您可以将您的observable从
CombineTest
更改为
openWorkbook

是否可以尝试将订阅(仅用于测试目的)添加到订阅类中
subs=newsubscription()
,然后通过写入以下内容将订阅添加到
subs
:subs.add(observeable$.subscribe(…)。在unsubscribe中,只需调用subs.unsubscribe()。如果这解决了您的问题,请通知我们。然后我们知道是因为订阅对象。我建议尝试:1。使用
takeUntil
操作员取消订阅,2。删除嵌套订阅-因此对this.webPlayerService.openWorkbook调用使用
switchMap
操作符。现在我看到问题了。感谢@vitaliy kotovs的评论。我实际上没有看到你在订阅中有订阅。内存泄漏的原因是,每当外部订阅发出时,都会覆盖对旧订阅的引用。这意味着您只能取消上次添加的订阅。上一篇文章将永远留在记忆中并发挥作用。谢谢你们两位的建议@vitaliykotov我过去确实试过服用,但运气不好。至于使用
switchMap
操作符,我不知道如何在我的用例中应用它。具体地说,不确定
开关映射(
“this.\u订阅[“webPlayerServiceSubscription”]=this.webPlayerService.openWorkbook(workbook.libraryPath,parameterString).pipe(开关映射()).subscribe(…)@JonathanStellwag这是否意味着你建议使用一个
subs
订阅在我的情况下不起作用?谢谢你,Vitaliy。非常感谢,这很有魅力。我还是RxJS的新手,你的输入(以及Jonathan Stellwag的输入)在这里吸取了教训-不要嵌套订阅。谢谢!