在路由器订阅中调用订阅方法时,我是不是应该取消订阅 ActivatedRoute?
Posted
技术标签:
【中文标题】在路由器订阅中调用订阅方法时,我是不是应该取消订阅 ActivatedRoute?【英文标题】:Should i unsubscribe from ActivatedRoute when calling subscribe method within a Router subscription?在路由器订阅中调用订阅方法时,我是否应该取消订阅 ActivatedRoute? 【发布时间】:2020-10-26 22:39:45 【问题描述】:我了解到,通常您不必明确取消订阅 Router
或 ActivatedRoute
,因为:
ActivatedRoute 及其 observables 与 Router 隔离 本身。当路由组件不再存在时,路由器会销毁它 需要,注入的 ActivatedRoute 也随之消亡。
来源:Do I have to unsubscribe from ActivatedRoute (e.g. params) observables?
但是我在父组件app.component
中反复调用ActivatedRoute.firstChild.paramMap
上的subscribe()
。该组件仅在用户离开 Web 应用程序或关闭网站时才会被销毁,所以我担心那些 paramMap
订阅可能会一直保持活动状态。
订阅调用是在 Router.events
订阅中进行的,如下所示:
this.routerSubscription = this.router.events
.pipe(
tap((event) =>
switch (true)
case event instanceof NavigationStart:
setTimeout(() => this.showChildComponentLoading = true);
break;
case event instanceof NavigationEnd:
this.activatedRoute.firstChild.paramMap.subscribe(paramMap =>
if(paramMap.has('mode'))
let newWebAppMode:string = paramMap.get('mode');
if(this.dataStoreService.isValidWebAppMode(newWebAppMode) && newWebAppMode !== this.dataStoreService.currentAppMode)
this.saveToLocalStorage.next([DataType.WEB_APP_MODE, newWebAppMode]);
);
//other code
每次有人导航到另一个组件/页面时,activatedRoute.firstChild.paramMap
都会再次被订阅。我必须在路由器订阅中执行此操作,并且仅当事件是 NavigationEnd
的实例时才这样做,因为在此之前 url 参数尚不可用。
我的问题是,这些订阅会发生什么?他们是自动退订还是我需要手动退订每个新的?如果是后者,我该如何有效地做到这一点?
你们中的一些人可能会建议我使用activatedRoute.firstChild.snapshot.paramMap.myParameter
,因为这样我就不必订阅任何东西了。但是,snapshot
在重复使用相同组件时 url 参数更改时不起作用。所以我不能用那个。
谢谢
【问题讨论】:
当你离开时,一切都被清除了,没有任何东西保持“订阅”,因为整个 js 上下文都被释放了 【参考方案1】:是的,它看起来确实像潜在的内存泄漏:在每个NavigationEnd
上都会产生一个新订阅,因此您可能有无限数量的相同流的相同观察者(并且activatedRoute.firstChild.paramMap
无限期发出)。您可以通过在订阅中添加一个简单的console.log(new Date())
来验证这一点。
我相信switchMap
是您的朋友(订阅新流时它会自动退订旧流)。某样东西
this.router.events.pipe(
filter(event => event instanceof NavigationEnd),
switchMap(() => this.activatedRoute.firstChild.paramMap),
filter(paramMap => paramMap.has('mode')),
map(paramMap => paramMap.get('mode')),
filter(newMode => this.dataStoreService.isValidWebAppMode(newMode) &&
newMode !== this.dataStoreService.currentAppMode),
).subscribe(newMode => this.saveToLocalStorage.next([DataType.WEB_APP_MODE, newMode]);
顺便说一句,你不需要防止this.activatedRoute.firstChild
为空吗?
【讨论】:
不,我不必提防这种情况。父组件总是显示一个子组件。我发现我不必取消订阅,因为它在后台重用了相同的 ActivatedRoute 实例。我在添加pipe(first())
时发现了这一点。 first()
将允许 ActivatedRoute 只发出一个值,然后它会自动完成。这意味着 ActivatedRoute 之后将不再工作。所以最好不要手动退订【参考方案2】:
在这些情况下无需退订
在 HttpClient 调用的情况下,因为 observable 发出一个值(成功或错误)并自动完成。
万一或ActivatedRoute订阅因为Router会在组件被销毁时自动销毁
使用异步管道
【讨论】:
the Router will destroy it when the component
是的,但是在浏览器关闭或用户离开网站之前,app.component
不会被销毁。这意味着这些订阅可以在内存中保持活跃,直到用户停止浏览网站。但我对此不确定,因此提出了这个问题。以上是关于在路由器订阅中调用订阅方法时,我是不是应该取消订阅 ActivatedRoute?的主要内容,如果未能解决你的问题,请参考以下文章
我应该取消订阅根 Angular 组件中的 observables 吗?