取消订阅服务内部的Observables?

时间:2018-08-10 17:00:41

标签: angular typescript observable subscriptions unsubscribe

在查看代码示例时,我经常看到没有取消订阅服务内部的可观察对象的情况。

这里是一个例子:

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 $?还是上面的例子只是编码错误导致内存泄漏?

2 个答案:

答案 0 :(得分:3)

对于核心服务,取消订阅实际上不是必需的,因为服务的寿命与应用程序的寿命相同,并且该服务是单例的。问题是您必须确保始终将其作为单例使用(有关更好的解决方案,请参阅下文)

对于组件服务,应将取消订阅置于服务的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作为开头。

答案 1 :(得分:0)

  

在查看代码示例时,我经常看到没有取消订阅服务内部的可观察对象的情况。

您正在寻找错误。

  

在这种情况下,您是否有理由不退订可观察到的this.isLoggedIn $?

如果您想泄漏内存。

  

还是上面的示例只是错误的编码导致内存泄漏?

是的,它正在泄漏内存。在this引用的对象被销毁之后,订阅函数将继续执行。如果此对象永不销毁,则可能永远不会发生,但这只是代码示例,它将使在临时创建对象的单元测试中失败。

标记为@Injectable()的对象通常表现为单例或具有弱引用。它可能会工作一段时间,但是在临时情况下使用它会泄漏内存。

相关问题