【问题标题】:How to run and stop the interval method in the subscribe if condition is met in Angular如果在Angular中满足条件,如何在订阅中运行和停止间隔方法
【发布时间】:2020-12-27 04:04:18
【问题描述】:

这里我有一个疑问,如何在订阅中调用间隔方法并在满足条件后停止它

下面是我的代码

主订阅方法

this.authservice.getdata().subscribe(response => {
   console.log(res)

   // Polling method
    
    SetInterval(()=>{
     this.getInterval();
   },5000)

})

间隔法:

getInterval(){
  this.authservice.getIntervalData().subscribe(resp => {
    console.log(resp)
   this.responseStatus = resp
  })
}

在响应中它给出了 3 种类型的响应

继续

停止

终止

所以在这里我需要在 Main subscribe 方法中调用 getInterval() ,直到 GetInterval 给我 Proceed 作为响应或直到轮询后 1 分钟我设置了运行间隔,如果满足其中任何一个条件我必须停止轮询。

注意:如果主订阅成功响应,我不需要轮询主订阅方法,那么只有我开始这个轮询

更新: 下面的方法有效,但在这里我需要两件事

  1. 如何设置变量并将响应存储在其中

  2. 如果响应来了,我如何根据 res 设置布尔变量

    this.content =true 同样明智

    因为当我尝试在 switchMap 中设置变量时,它不接受

    this.authservice.getdata().pipe( switchMap(resp => timer(0, 5000).pipe( // 需要将此响应存储在全局变量中,以便进一步使用 switchMap(t => this.authservice.getIntervalData().pipe( map(data => [data, t]))) takeWhile(([data, t]) => data !== 'TERMINATE' && t 数据) )) ).subscribe(data => console.log(data))

【问题讨论】:

  • getIntervalData 的第二个 api 调用,之后您想使用第一个的结果进行另一个调用?
  • @RafiHenig 在调用 getdata() 结果后,我将在获取 getInterval 方法的结果后作为 get Interval 方法的参数发送,我将根据条件设置布尔值跨度>
  • @Madpop 请看我的更新
  • @RafiHenig 最后一件事在使用间隔(5000)时我们正在调用方法 .getIntervalData 如果在间隔数据中获得响应作为终止并且如果它没有得到终止,则必须停止然后需要每 5 秒间隔 2 分钟,我们可以在方法之外停止这个间隔吗?我的意思是像点击按钮一样?
  • @Madpop 请看我的更新

标签: javascript angular rxjs angular-httpclient


【解决方案1】:

考虑如下实现它:

this.authservice.getdata().pipe(
  tap(x => this.globalVariable = x),
  switchMap(data => interval(5000).pipe(
    switchMap(x => this.authservice.getIntervalData(x)), //<== pass data from first subscription to second
    takeUntil(timer(60 * 1000)),
    takeWhile(x => x !== 'TERMINATE'),
    map(data2 => [data, data2]) // <= return values from both subscriptions 
  ))

更新:

“在方法之外停止这个间隔,我的意思是像点击按钮一样”

clicked$ = new Subject<void>();

onclick(){
  this.clicked.next(); // on click emit value
}


this.authservice.getdata().pipe(
  tap(x => this.globalVariable = x),
  switchMap(data => interval(5000).pipe(
    switchMap(x => this.authservice.getIntervalData(x)), //<== pass data from first subscription to second
    takeUntil(timer(60 * 1000)),
    takeWhile(x => x !== 'TERMINATE'),
    map(intervalDataRes => this.condition = intervalDataRes),
    takeUntil(merge(this.clicked$, timer(2 * 60 * 1000))) // interval will stop after 2 or as soon as clicked$ emits
  ))

【讨论】:

  • 不确定我是否同意这更简单,它只是使用第二个计时器,但无论如何,timer(0, 5000) 优先于interval(5000),因为timer 将立即启动,而interval 将最初等待 5秒。
  • 我可以得到第一次订阅的价值吗?
  • 当然。您从两个订阅中接收值作为单个数组 [first, second],
  • 我的意思是使用 getData() 我会得到一些值,我必须将这些值发送到 getIntervvaldata(resp) ?
  • @RafiHenig 我还有最后一个疑问
【解决方案2】:

你可能只想使用操作符和 observables....

this.authservice.getdata().pipe( // get initial data
  tap(resp => this.myVariable = resp),
  switchMap(resp => timer(0, 5000).pipe( // switch to timer that emits every 5 seconds
    switchMap(t => this.authservice.getIntervalData().pipe( // swtich again to interval data
      map(data => [data, t]))) // map to response and timer value
    takeWhile(([data, t]) => data !== 'TERMINATE' && t < 12), // whatever stop condition, this says stop when the data is terminate or the timer has emitted 12 times (1 minute if emitting every 5 seconds)
    map(([data, t]) => data) // just send the data through
  ))
).subscribe(data => console.log(data))

我将如何实现这一点。

【讨论】:

  • 但我已经在组件中有订阅方法。在将结果返回到组件级别之后,我在使用管道方法的服务中
  • 这里首先我需要让第一个 getdata 方法成功,如果订阅成功,那么我需要调用间隔方法
  • 如果第一次订阅不成功则不调用定时器
  • 您可以根据需要构建服务。只需将这一切封装在一个服务中并返回可观察的。这无关紧要。至于下面的 cmets,这就是 observables 总是这样工作的。失败会跳过流的其余部分。
  • 你的意思是如果第一次订阅工作,那么间隔工作,如果第一次订阅失败,那么间隔也失败?
【解决方案3】:

考虑使用Subject 来存储全局变量。这样您就可以完全避免订阅

以下解决方案在 stackblitz 上测试,see this link

  // Emit Once after 60 Seconds
  stopTime$ = timer(60000);

  // TerminateResponse
  terminateSubject$ = new Subject();
  terminateAction$ = this.terminateSubject$.asObservable();

  // Emits Every 5 seconds until stopTime is called
  interval$ = timer(0, 5000).pipe(
    takeUntil(this.stopTime$),
    takeUntil(this.terminateAction$),
  );

  // Global Variable
  responseSubject$ = new Subject()
  responseAction$ = this.responseSubject$.asObservable();

  // Create Interval Observable. This will call getIntervalData until no more interval
  intervalData$ = this.interval$.pipe(
    switchMap(() => this.authservice.getIntervalData()),
    tap(res => this.responseSubject$.next({res, content: true})),
    tap(res => res === 'Terminate' ? this.terminateSubject$.next(true): ''),
  
  )

我们定义一个变量

stopTime$ = timer(60000);

这会在 60000 毫秒后发出一次,即 1 分钟

接下来我们定义

 terminateSubject$ = new Subject();
 terminateAction$ = this.terminateSubject$.asObservable();

当条件满足时,我们将使用这个 observable 来终止计时器,使用 takeUntil 运算符并在 observable 上调用 next() 函数

然后我们定义

interval$ = timer(0, 5000).pipe(
    takeUntil(this.stopTime$),
    takeUntil(this.terminateAction$),
  );

此 observable 将每 5000 毫秒以 0 延迟发射,直到调用 stopTime$ observable 或调用 terminateAction$

然后我们创建一个主题来存储我们的全局变量。由于 observables 是异步的,为了避免未定义的值,使用 observables 来存储我们的变量并在需要时订阅这些变量是有意义的

  responseSubject$ = new Subject()
  responseAction$ = this.responseSubject$.asObservable();

最后我们定义了我们的区间 Data Observable

  intervalData$ = this.interval$.pipe(
    switchMap(() => this.authservice.getIntervalData()),
    tap(res => this.responseSubject$.next({res, content: true})),
    tap(res => res === 'Terminate' ? this.terminateSubject$.next(true): ''),

  )

tap(res =&gt; this.responseSubject$.next({res, content: true})) 存放全局变量 tap(res =&gt; res === 'Terminate' ? this.terminateSubject$.next(true): '') 终止可观察区间

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多