Angular 角度:如何在定期请求时取消订阅

Angular 角度:如何在定期请求时取消订阅,angular,rxjs,Angular,Rxjs,我有一个角度组件,定期从服务请求值: setInterval(() => { this.updateValues(); }, 1000); updateValues(): void { if (this.isValuesUpdateRunning === false) { this.isValuesUpdateRunning = true; this.apiService.getCurrentValues().subscribe((data: a

我有一个角度组件,定期从服务请求值:

setInterval(() => {
      this.updateValues();
    }, 1000);


updateValues(): void {
  if (this.isValuesUpdateRunning === false) {
    this.isValuesUpdateRunning = true;
    this.apiService.getCurrentValues().subscribe((data: any) => {
      if (data != null) {
        this.currentValues = data;
        this.isValuesUpdateRunning = false;
      }
    });
  }
}
我很确定我应该在某个地方取消订阅这项服务,因为我确实通过这样做打开了很多订阅。我正在考虑使用异步管道,但是我需要设置“isValueUpdateRunning”变量,如果我只是在模板中使用异步,这是不可能的

另外,在Angular提供的“onDestroy”方法中取消订阅也没有帮助,因为据我所知,这个方法只有在我离开页面时才会被调用。但我需要更频繁地关闭订阅,以防止数千个订阅保持打开状态

我还尝试在设置值后立即关闭订阅,但在视图中没有任何值:

updateValues(): void {
  if (this.isValuesUpdateRunning === false) {
    this.isValuesUpdateRunning = true;
    const sub = this.apiService.getCurrentValues().subscribe((data: any) => {
      if (data != null) {
        this.currentValues = data;
        this.isValuesUpdateRunning = false;
      }
    });
    // closing the subscription right here:
    sub.unsubscribe();
  }
}

你能帮忙吗?我已经没有主意了。

如果使用的是angular http客户端,您不需要像@Kurt Hamilton提到的那样取消订阅服务。您需要停止正在创建订阅的设置间隔

使用rxjs运算符的示例

interval(1000)
   .pipe(
     takeWhile(() => this.isValuesUpdateRunning), // call subscription until the condition is false
     switchMap(() => this.apiService.getCurrentValues()),
     filter(Boolean), // check if response is not null
     tap(resp => { this.data = resp; this.isValuesUpdateRunning = false; }),
     // handle errors 

您可以在收到如下所示的响应后关闭订阅。另外,请注意,如果从getCurrentValues()调用AJAX API,则HTTPObservable是自动关闭的,因为一旦获得http响应,http客户端将完成订阅,因此无需关闭订阅

 updateValues(): void {
      if (this.isValuesUpdateRunning === false) {
        this.isValuesUpdateRunning = true;
        const sub = this.apiService.getCurrentValues().subscribe((data: any) => {
          if (data != null) {
            this.currentValues = data;
            this.isValuesUpdateRunning = false;
          }
         // closing the subscription right here:
         sub.unsubscribe();
        }, error => { sub.unsubscribe});

      }
    }

假设您正在模板中呈现
currentValues
,我建议使用异步管道

根据
isValuesUpdateRunning
逻辑,您可以使用
defaustmap
并用RxJS间隔替换setTimeout

我在下面放了一个演示—我强烈建议您学习模拟api服务,并亲自尝试这些东西

const currentValues$ = interval(1000)
  .pipe(
    tap(i => console.log(`timer::${i}`)),
    exhaustMap(i => apiService.getCurrentValues(i)),  // ignores new values until api returns
    tap(apiData => console.log(`api::${apiData}`)),
    filter(data => !!data)                            // filter for truthy values
    takeUntil(stopClick$),                            // or this.destroyed$ component logic
  )
(这假设在模板中使用异步管道,例如
{{currentValues$|async | json}}

更新-最好把take放在最后

工具书类
-如果此.apiService.getCurrentValues()正在使用angular
HttpClient发出http请求,则忽略新发出的值,直到当前observable完成(angular http请求自动完成)

,你不需要取消订阅。你没有获得价值,因为你在得到答案之前没有订阅。我同意上面关于http请求的评论。@KurtHamilton我正在使用HttpClient,是的。这只是一个简单的get请求。你觉得我根本不需要退订?我认为它总是需要的,除非你使用异步管道。@Manuela取消订阅并没有什么坏处,事实上,如果你不想让subscribe中的逻辑运行,比如api调用挂起,并且你移动到了应用程序的另一个部分,而这不是必须的。更新后,问题似乎是我今天早上没有喝咖啡。很抱歉成为那个家伙,但这将立即取消订阅
takeUntil
将立即从
BehaviorSubject
接收一个值<代码>条件$
只能是普通的ol'
主题
。更新的示例。不,这很好,我有错误的假设,你完全正确。检查了文档。也许使用takeWhile和使用变量的谓词是正确的方法。我的想法有点不同,我想使用这个值,而不是触发订阅。