【问题标题】:How can i unsubscribe all subscriptions in my app?如何取消订阅我的应用程序中的所有订阅?
【发布时间】:2020-08-13 12:51:13
【问题描述】:

我有一个大型应用程序,其中有很多订阅方法。如果我想退订其中一个,那么我将使用以下代码:

getUsersSubscription: Subscription;

ngOnInit() : void {

   this.getUsersSubscription = this.userService().subscribe(users => {
     ...something
   })
}

ngOnDestroy() : void {
   this.getUsersSubscription.unsubscribe();
}

问题是我有很多页面 - 也有组件。我有 jwt 令牌,当它过期时,我正在注销用户。问题是当我这样做时,一些电话仍在发生......我如何在注销后取消订阅我的应用程序中的所有内容,这样我就不需要通过页面中的所有组件对我的所有订阅重复此步骤?

另外,我正在使用拦截器来捕获 jwt 过期并将用户重定向到登录页面。但是,如果用户单击某些内容,登录页面中仍然会进行调用 - 在他注销前几秒钟

【问题讨论】:

  • 你应该使用拦截器并检查状态码。如果你得到 401 然后在登录屏幕上重定向。
  • 我正在使用它。当我重定向到登录页面时,仍然会拨打一些电话,因为并非所有订阅都已取消订阅

标签: angular rxjs


【解决方案1】:

如果你需要退订很多Observable,你应该使用Subscription数组:

private subscriptions: Subscription[] = [];

ngOnInit() {
    this.subscriptions.push(this.userService.subscribe(users => {
     ...something
   }));
}

ngOnDestroy() {
    this.subscriptions.forEach(subscription => subscription.unsubscribe());
}

但我认为您真正的问题是您的订阅量可能比您需要的多。

首先,您应该尽可能使用async 管道。它可以很好地免费处理订阅和取消订阅。

另外,请注意,您通常不需要取消订阅冷的 observable(如 HttpClient 返回的那些),因为当 http 请求完成时,observable 会终止。 您只需取消订阅具有副作用的冷可观察对象。

【讨论】:

  • 感谢您的回复。当他应该使用右侧的订阅进行初始化时,我将如何将我的 this.getUsersSubscription 放入该数组中?
  • 对不起,我忘了初始化数组。我更新了示例
  • 在代码进入ngOnInit之前初始化数组。 this.userService.subscribe(...) 返回一个 Subscription 对象,该对象将被推送到数组中。
  • 顺便说一句,您确实需要在 Angular 应用程序中取消订阅冷的 observables,因为如果有一个待处理的 http 请求,并且您将页面更改为另一个路由,该请求将不会被取消,除非你取消订阅它在组件的 onDestroy 方法上是可见的。
  • @AliDemirci 感谢您的评论。如果你取消订阅一个cold observable,http请求不会被取消,但至少你的应用会忽略这个结果。
【解决方案2】:

与之前的选项不同,您不妨走以下路线:

您可以使用takeUntil()operator,一旦发生特定事件,它会自动为您取消订阅。 例如:

在某些组件中

...

myObservable$ = this.service.foo().pipe(
  takeUntil(this.loginService._loggedOutEmitter) <-- (0)
).subscribe()

...

在登录服务中

...

_loggedOutEmitter = new Subject<boolean>(); <---- (1)

loggedOut() {
  *some logout logic *
  this._loggedOutEmitter.next(true); <----------- (2)
}

...

就像在其他解决方案中一样,您必须导入特定服务,并且需要为每个 Observable (0) 添加特定行,但这种方式在内存方面应该稍微友好一些,因为您不需要跟踪您的订阅。 相反,您只有一个 Observable (1),它发出一次 (2)。

我仍然觉得你提出的方式(在 OnDestroy 中清除 [顺便说一下,我认为也应该使用 takeUntil() 方法来完成])更干净。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-19
    • 2012-03-14
    • 1970-01-01
    • 2019-07-02
    • 2015-08-24
    • 2020-06-03
    相关资源
    最近更新 更多