【问题标题】:Angular4 - do I need to unsubscribe from setTimeout calls?Angular4 - 我需要取消订阅 setTimeout 电话吗?
【发布时间】:2018-04-05 08:22:47
【问题描述】:

在一些地方我需要调用 setTimeout,例如:

setTimeout(() => this.isSaving[index] = false, 500);

当我的组件被销毁时,该超时是否会继续发出?换句话说,我是否需要捕获返回的 observable,如下所示:

this.subTimeout = setTimeout(() => this.isSaving[index] = false, 500);

然后在我的销毁钩子中取消订阅:

ngOnDestroy() {
  this.subTimeout.unsubscribe();
}

如果我必须在我的组件中启动多个 setTimeouts,这会变得很费力。有没有更简单的方法来摧毁它们?可能像 takeUntil(destroy$) 一样?

【问题讨论】:

  • 如果您想要一种方便的方式来执行 takeUntil(destroy$),您可以查看这个问题:stackoverflow.com/questions/40737752/…
  • 谢谢,但我认为,由于您无法订阅 setTimeout,因此您无法使用 takeUntil(destroy$)。此外,您提供的链接使销毁订阅过于复杂。你不需要装饰器,你只需要一个主题: private destroy$ = new Subject(); ngOnDestroy() { this.destroy$.next(); }
  • 如果你希望它是可观察的,你可以使用Observable.timer(1000) 而不是setTimeout。至于它过于复杂,我使用基类版本,它简化了销毁,因为如果它们是在 ngOnInit 中创建的,我不必跟踪订阅或处理空检查。它还允许通过 onChanges 观察 @Inputs。
  • @bygrace 谢谢,我不知道 Observable.timer(1000)。
  • @bygrace 我看到了基类解决方案的优势,但我现在必须检查所有组件,更改它们以继承它,然后检查我实现的每个生命周期钩子以调用 super.由于我已经将 next.destroy$ 包含在其中,因此至少现在保持这种方式更容易。但是感谢分享那篇文章,我给了它一个 +1,因为它很有用。

标签: javascript angular rxjs settimeout


【解决方案1】:

我是否需要取消订阅 setTimeout 调用?...当我的组件被销毁时,该超时是否会继续发出?

您无需担心回调会重复执行。 setTimeout 只执行一次然后就死了。考虑到时间将用完并且回调仅在组件被销毁后才执行的可能性通常是一种好习惯。在我自己的应用程序中,我将所有需要撤消的订阅放入一个数组中,并且我在ngOnDestroy 中有一个标准的批量取消订阅作业。您的超时也可以这样做:

// component property
timeOutIDs:number[] = [];
...
// triggering a timeout and capturing the id
this.timeOutIDs.push(
    setTimeout(() => this.isSaving[index] = false, 500)
);
...
// inside ngOnDestroy
this.timeoutIDs.forEach(id => clearTimeout(id));

使用这种方法,您将不需要多个变量来存储不同的超时 id,并且如果您始终在 ids 数组中使用push 的返回值setTimeout,您可以确保所有超时都将被正确清除。

附加说明:您应该始终取消 setInterval 呼叫并始终取消订阅开放式订阅。

【讨论】:

  • 如果组件在setTimeout 触发之前被释放会发生什么?
  • 感谢您的快速回答 - 并指出 setInterval 是必需的。我会错过的。开放式订阅我学到了艰难的方式,哈哈;)
  • 好吧,他问“当我的组件被销毁时,超时会继续发出吗?”。简单的回答是:是的。更不用说不管设置延迟都清理它的好习惯. 为了省事,如果他不想考虑这些事情,他会使用Observable.timer
  • 您可能希望将 cmets 中的这个小谈话整合到您的答案中,以便我们对其进行投票;)
  • 不客气!感谢您展示的非常好的清洁程序!
【解决方案2】:

这取决于setTimeout 回调中发生的事情,但通常它们应该被取消订阅。他们不可能神奇地被取消订阅。他们的回调会以任何方式被触发,并可能导致错误或不良副作用。

最好将超时分配到某个地方,至少出于测试目的。 ngOnDestroythis.subTimeout.unsubscribe()中应该做的事情,假设是通过RxJS进行了超时:

this.subTimeout = Observable.timer(500).subscribe(() => { 
  this.isSaving[index] = false;
});

改进的方式取决于这些超时的用途。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-30
    • 2022-01-02
    • 1970-01-01
    • 2020-07-23
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 2017-06-22
    相关资源
    最近更新 更多