为啥我要使用 RxJS 的 interval() 或 timer() 轮询而不是 window.setInterval()?
Posted
技术标签:
【中文标题】为啥我要使用 RxJS 的 interval() 或 timer() 轮询而不是 window.setInterval()?【英文标题】:Why would I use RxJS interval() or timer() polling instead of window.setInterval()?为什么我要使用 RxJS 的 interval() 或 timer() 轮询而不是 window.setInterval()? 【发布时间】:2019-01-31 18:51:41 【问题描述】:用例: 每分钟(60000 毫秒)调用一个函数,该函数调度存储操作以获取项目的lastUpdated
状态,在响应和过滤后,更新存储,并读取更新的存储作为可观察的并显示在视图中)。只要网络应用程序处于打开状态(无限期地),这种情况就需要发生。
目前,我正在使用这个:
this.refreshDate = window.setInterval(
() => this.store.dispatch(new FetchLastUpdate())
, 60000);
当视图被销毁/卸载时,我删除了间隔:
if (this.refreshDate)
clearInterval(this.refreshDate);
这是高效/有效,还是很麻烦?
我为什么要使用 RxJS 轮询策略,例如:
interval(60000)
.pipe(
startWith(0),
switchMap(() => this.store.dispatch(new FetchLastUpdate()))
);
或者
timer(0, 60000)
.pipe(
switchMap(() => this.store.dispatch(new FetchLastUpdate()))
);
TL;DR: window.setInterval()
与 RxJS timer()
/interval()
结论/答案(便于研究):
使用 RxJS 函数设置间隔或执行轮询有很大的好处,这些好处在 selected answer 和 cmets 中都有解释,但得出的结论是(通过 cmets 中的讨论)对于非常简单的要求在本文开头的“用例”部分定义的,没有必要使用 RxJS,事实上如果你在程序的任何其他部分没有使用 RxJS,请不要导入它只是为了这个,但就我而言,我已经在其他地方导入并使用了 RxJS。
【问题讨论】:
我认为FetchLastUpdate
的持续时间不会超过60
秒,所以使用switchMap
似乎有点矫枉过正,我宁愿使用setInterval
,这对于您的用例来说似乎已经足够了
@OlivierBoissé 对,这就是我一直在假设和坚持的,但我想我会寻求其他更有经验的意见。至于switchMap,你是对的,点击可能会更好。
此外添加rxjs
会增加你的js包大小,所以如果你在其他地方不需要它,你可以跳过它并使用setInterval
@OlivierBoissé 确实如此,但由于您提到的原因(在其他地方使用),它不适用于我。谢谢:)
【参考方案1】:
RxJS 的优势:
懒惰
你可以创建你的 Observables,直到你调用 subscribe
之前什么都没有发生。 Observable = 纯函数。这为您提供了更多的控制权、更容易的推理并允许下一点......
可组合性
您可以将interval/timer
与其他operators
以统一的方式非常容易地组合创建自定义逻辑 - 例如您可以map
、repeat
、retry
、take
...等see all operators
错误处理
如果发生错误,您有责任致电clearTimeout/clearInterval
- Observables 正在为您处理此问题。导致更简洁的代码和更少的内存泄漏错误。
当然,你用 Observables 做的任何事情你也可以不用 Observables 做——但这不是重点。 Observables 让您的生活更轻松。
另请注意,interval/timer
不是用于轮询的可观察工厂,因为它们不会“等待”您的异步操作完成(您最终可能会遇到多个异步调用相互运行)。为此,我倾向于像这样使用defer
和repeatWhen
:
defer(() => doAsyncAction())
.pipe(
repeatWhen(notifications => notifications.pipe(delay(1234)))
);
【讨论】:
感谢您提供信息丰富的答案,这些现在绝对是我下次投票或类似的事情时会考虑的事情,因此您的回答有助于了解interval()
/timer()
(或defer()
)与纯 JS 相比的好处,但考虑到我在帖子本身中定义的用例,我认为这种类型的使用不会获得任何好处。跨度>
如果您对 rxjs 没有其他用途,那么当然 - 使用 window.setInterval
但请确保您的 FetchLastUpdate
操作不会超过 60 秒 :)
另外,为了澄清为什么我看不到这个用例的任何好处,我发表了另一条评论:如果要求只是调用,则无需创建整个(干净的)逻辑每分钟一个函数。我不需要任何错误处理,因为我的 FetchLastUpdate()
操作会处理它自己的所有错误,商店会处理自己的错误,以及异步 HTTP 调用。虽然自动清理是有益的,所以我不必调用clearInterval()
,但我不确定这是否值得为了避免这种情况而调用 RxJS 函数的开销。虽然我可能高估了这一点。
(这是对您的评论回复的回复)好的,这很好。 @OlivierBoissé 也支持该声明。谢谢你:)
由于信息布局清晰,我选择了您的答案作为帖子的答案,并且它代表了此类 RxJS 策略而不是纯 JS 的普遍使用。 @OlivierBoissé 将他的答案作为这个用例的最终答案,但他没有发表答案帖子,只是对帖子本身发表评论。【参考方案2】:
window.setInterval
不关心你的回调状态,尽管过去回调的执行状态如何,它都会在给定的时间间隔执行,让它停止和跳过的唯一方法是清除间隔或重新初始化它。
另一方面,基于 RxJS Observable 的解决方案(interval
,timer
)允许您使用管道条件运算符(例如takeWhile
,skipWhile
),它允许您添加停止或实现停止-只需翻转一个布尔标志即可启动逻辑,而不是添加清除间隔然后重新创建它的复杂逻辑。
它们是可观察的,您可以在整个应用程序中监听它们,并附加任意数量的监听器。
错误处理也更好,您订阅所有成功,并在 catch 回调中处理所有内容。
【讨论】:
错了!如果window.setInterval
有一个基于 XHR 的回调,你可以使用 async/await 让它等待。 Ramda 和其他库只是矫枉过正。
@Adeel 您有示例代码来执行您的建议吗?据我了解,即使在最后一个完成之前,也无法阻止 setInterval 再次运行回调?
感谢您的回复。在@m1ch4ls 的帖子之前我没有看过你的帖子,我对此发表了评论。但基本上,你是对的,我下次投票时肯定会考虑这些点,因为我以前没有考虑过它们。轻松、干净地访问这些运算符以及更灵活的错误处理是非常有利的。其他案例/阅读本文的人将从这些要点中受益,但是我看不出这些将如何使我的具体案例受益。我将在此处的下一条评论中粘贴我其他评论中的原因。
另外,为了澄清为什么我看不到这个用例的任何好处,我发表了另一条评论:如果要求只是调用,则无需创建整个(干净的)逻辑每分钟一个函数。我不需要任何错误处理,因为我的 FetchLastUpdate()
操作会处理它自己的所有错误,商店会处理自己的错误,以及异步 HTTP 调用。虽然自动清理是有益的,所以我不必调用clearInterval()
,但我不确定这是否值得为了避免这种情况而调用 RxJS 函数的开销。虽然我可能高估了这一点。
@Chris 这是我制作的一个简单示例codesandbox.io/s/q80j06y516,请注意我在此示例中获取随机用户的位置。我可以将它包装在 try/catch 中并清除我的时间间隔并执行错误处理。希望这会有所帮助。以上是关于为啥我要使用 RxJS 的 interval() 或 timer() 轮询而不是 window.setInterval()?的主要内容,如果未能解决你的问题,请参考以下文章