取消订阅服务内部的 Observables?
Posted
技术标签:
【中文标题】取消订阅服务内部的 Observables?【英文标题】:Unsubscribing from Observables inside services? 【发布时间】:2019-01-18 08:05:17 【问题描述】:在查看代码示例时,我经常看到服务内部的 observable 没有被取消订阅的情况。
这是一个例子:
export class AuthGuard implements CanActivate
private isLoggedIn: boolean;
private isLoggedIn$: Observable<boolean>;
constructor(private authService: AuthService, private router: Router)
this.isLoggedIn$ = this.authService.isLoggedIn();
this.isLoggedIn$.subscribe(res =>
if (res)
this.isLoggedIn = true;
else
this.isLoggedIn = false;
);
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot)
if (this.isLoggedIn)
return true;
else
this.router.navigate(['login']);
return false;
在这种情况下,您是否有理由不取消订阅可观察的 this.isLoggedIn$?还是上面的例子只是糟糕的编码导致内存泄漏?
【问题讨论】:
Is it necessary to unsubscribe from observables created by Http methods?的可能重复 brianflove.com/2016/12/11/anguar-2-unsubscribe-observables 请访问这篇文章无论如何上面它只是糟糕的编码示例 我在问这个问题之前已经阅读了这篇文章....这篇文章没有涉及任何关于是否应该取消订阅 observables 的问题,即使 observable 不包含在组件中而是包含在服务 @Vlad274:我现在不必取消订阅由 http 方法创建的 observables ......但是由 Services 创建的 observables 呢? 【参考方案1】:对于核心服务,取消订阅并不是真正必要的,因为服务与应用程序一样存在,而且服务是单例的。问题是您必须确保始终将其用作单例(要获得更好的解决方案,请阅读下文)
对于组件服务,取消订阅应该放在服务的ngOnDestroy
内,因为服务实际上可以实现这个NgOnDestroy
挂钩。更好的方法是使用 takeUntil(this.destroy)
管道并在销毁时发出它。
更好的方法是在模板中使用async
管道,并且永远不要真正直接订阅此类内容。
另一方面,在您的守卫中,您可以使用take(1)
管道,这将采用第一个发射并立即取消订阅,而无需您这样做,这会将您的示例更改为这个。如您所见,代码内没有订阅:
export class AuthGuard implements CanActivate
constructor(private authService: AuthService, private router: Router)
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot)
return this.authService.isLoggedIn().pipe(
take(1),
tap((loggedIn) =>
if (!loggedIn)
this.router.navigate(['login'])
)
);
最后,尝试使用模板内部的异步和 rxjs 管道函数让您的应用程序成为 Observable 流,而不是订阅和存储子结果。要使isLoggedIn()
在订阅时发出最后一个结果,您可以使用shareReplay()
管道或将其设置为BehaviourSubject
开头。
【讨论】:
我个人认为不要取消订阅,因为“它永远存在”是一种不好的做法。事情可能会发生变化,这是一个实现细节。如果您确定生命周期,您真的会记得经历并修复所有问题吗? @IngoBürk 这正是我在第一段中所说的 :) 并在其余答案中对此进行了更详细的说明【参考方案2】:在查看代码示例时,我经常看到服务内部的 observable 没有被取消订阅的情况。
您正在查看一个错误。
在这种情况下,您是否有理由不取消订阅可观察的 this.isLoggedIn$?
如果你想泄漏内存。
或者上面的例子只是糟糕的编码导致内存泄漏?
是的,它正在泄漏内存。订阅函数会在this
引用的对象被销毁后继续执行。如果这个对象永远不会被销毁,它可能永远不会发生,但这是一个代码示例,它会导致临时创建对象的单元测试失败。
带有@Injectable()
标记的对象通常表现得像单例或具有弱引用。它可能会工作一段时间,但一旦你在临时情况下使用它,它就会泄漏内存。
【讨论】:
以上是关于取消订阅服务内部的 Observables?的主要内容,如果未能解决你的问题,请参考以下文章