【问题标题】:interval rxjs not clearing timer间隔 rxjs 不清除计时器
【发布时间】:2020-10-19 14:37:56
【问题描述】:

我有一个 Input 属性作为 setter:

   @Input() set moduleData(value: any) {
    this._moduleData = value;
    this.destroy$.next();
    this.destroy$.complete();
    this.startAttempt();
  } 



  startAttempt() {
    if (!this.isExamStarted()) {
      console.log("exam is not started");
      interval(1000).pipe(takeUntil(this.destroy$)).subscribe((res) => {
        if (
          this.canStartAssessment(this.moduleData.module_progress.start_time)
        ) {
          console.log("exam can be started now");
          this.getTimeRemainingInExam();
        } else {
          this.getTimer(
            this.moduleData.module_progress.start_time,
            false
          );
        }
      });
    } else {
      this.getTimeRemainingInExam();
    }
  }


ngOnDestroy(): void {
    console.log("componenet destroyef");
    this.destroy$.next();
    this.destroy$.complete();
  }

通过使用 takeUntil 运算符,我试图停止计时器。我可以看到即使在组件被销毁后计时器仍然运行。此外,当输入属性发生变化时,我可以看到在 1 秒内它被调用了两次。例如,日志打印两次,与先前值的输入一样多。再次开始区间前输入属性发生变化时如何清除所有区间?

【问题讨论】:

  • 您的intervaltakeUntil(destroy$) 永远不会完成。 destory$ 在间隔开始之前已经完成。一旦流完成或出错,它就完成并且永远不会再次发出另一个值。对已完成的主题调用 .next() 无效。

标签: angular rxjs


【解决方案1】:

您不必complete 多播可观察destroy$

  1. 一旦完成,它们就不会再次启动。
  2. 如果 observable 仅用于 takeUntil,则 complete 是多余的。只需next 就足够了。参考here

试试下面的

@Input() set moduleData(value: any) {
  this._moduleData = value;
  this.destroy$.next(); // <-- `complete()` not required
  this.startAttempt();
}

...
ngOnDestroy(): void {
  console.log("component destroyed");
  this.destroy$.next(); // <-- `complete()` not required
}

【讨论】:

  • 谢谢。我知道这不是必需的,但不能解决我面临的问题。
  • @MohitHarshan 这应该可以解决您的问题。你的问题是你在set moduleData 中调用this.destroy$.complete()。因此,您在调用startAttempt 之前完成destroy$,从那时起destroy$ 将无法向takeUntil 发送任何通知。
【解决方案2】:

.subscription 必须被杀死。你可以添加这个sn-p

interval(1000).pipe(takeUntil(this.destroy$)).subscribe((res) => {
  [...]
});

进入订阅数组并在 ngOnDestroy 生命周期挂钩中取消订阅。

subscriptions: Subscription[] = [];

startAttempt() {
  [...]
  this.subscriptions.push(
    interval(1000).pipe(takeUntil(this.destroy$)).subscribe((res) => {
      [...]
    })
  )
  [...]
}

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

【讨论】:

    猜你喜欢
    • 2019-10-04
    • 2022-01-22
    • 2017-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多