RxJS按间隔轮询并在手动调用时

时间:2017-09-21 06:50:39

标签: notifications rxjs observable rxjs5 subject

在我的Angular应用程序中,我处理通知,并且我有一个REST API来调用最新用户的通知。我需要在几分钟内调用此API,因为用户实时收到通知并不是很重要(他们可能甚至不会出现这么快)。但是,下一步是在客户端刷新通知的想法:

  • 当用户登录开始刷新通知时 - 这是第一次手动调用,在几分钟后开始刷新API
    • 如果用户离开应用程序或只是浏览应用程序,则不要更改计时器并等待其余时间
    • 如果用户打开子页面,可以执行与通知相关的操作并执行此操作,则刷新通知并重置计时器
  • 刷新通知,直到退出

我已经有了所描述程序的工作代码,但我不确定它是否符合我的要求。以下是执行调用的代码(对于手动检查,只有一个主题,并且对于停止检查,存在对可观察的订阅 - 下面的代码实际上是分开的,但由于可读性,这里在一个地方):

// Subject for manual triggering
this.checkFeed = new Subject<void>();

// Call for refresh in own method
this.checkFeed.next();

// Waiting for manual refresh or triggering it on some interval after it was last triggered
this.feedSub = this.checkFeed.asObservable()
      .switchMap(() => Observable.timer(0, this.interval))
      .mergeMap(() => this.fetchChanges())
      .distinctUntilChanged(this.compareFeed)
      .subscribe(res => this.notify(res));

// Unsubscription when logging out
if (this.feedSub) this.feedSub.unsubscribe();

我最不确定的部分是.switchMap(() => Observable.timer(0, this.interval)),因为它需要0立即开始(这没关系,但仍然看起来不正确?) 。那么有没有更好的方法来实现我所描述的呢?

我还有另一个问题,如何开始检查来自另一个observable的通知 - 我应该使用哪个运算符。正如我所提到的,我已经用自己的方法调用了下一个主题:

refreshFeed(): void {
  this.checkFeed.next();
}

所以当有一些其他可观察的表演时(通知应该被刷新的动作)我需要调用这个。当其他observable响应API时,调用void方法的正确方法是什么?我在考虑这样的事情:

someActionThatCanChangeNotifications(): Observable<any> {
  return this.api.get('path/to/endpoint')
    .do(() => this.feedService.refreshFeed());
}

这样可以,还是有更好的方法?

提前感谢您的帮助!

2 个答案:

答案 0 :(得分:0)

所以基本上你有两个可观察的。

您手动调用的一个:

this.checkFeed

和间隔(让我们的callit intervalObs):

this.intervalObs = Observable.timer(0, this.interval);

如果您这样看,最简单的方法是合并您的两个源流,然后做任何您想做的事。

var mergedSource = Observable.merge(
    this.checkFeed,
    this.intervalObs)

subscription = mergedSource.subscribe(this.fetchChanges());

也许您需要在两者之间进行更多操作,但这应该会为您提供更具可读性的替代方案。

如果你想要玩一些https://plnkr.co/edit/n4nNFEMa4YOh2KSjDpSJ?p=preview

的东西,你可以试试这个工作的plunker

答案 1 :(得分:0)

从我所看到的你已经“正确地”完成了它。与一般的编程一样,单个问题有许多可能的(和正确的)解决方案。我个人也这样做。

我可以就你提到的两点给你一些评论:

.switchMap(() => Observable.timer(0, this.interval))

Observable.timer几乎是Observable.interval,在第一个值之前有自定义超时。 Observable.timer(0, this.interval)是正确的用法。

替代方案可以是Observable.just(0).concat(Observable.interval(this.interval)),它会立即返回一个值,然后开始间隔。我更喜欢你的方式;我认为它清楚地表明了你的意图:“在0毫秒之后产生一个值,然后产生this.interval”的间隔。

.do(() => this.feedService.refreshFeed())

我认为这是完全正确的做法。 do用于副作用,例如。发生在外面可观察物的东西。

我可以说,我不希望someActionThatCanChangeNotifications开始刷新Feed。当一个函数返回一个observable时,我希望返回一个没有任何副作用的observable。然而,当我们生活在一个不完美的世界时,我们不能总是拥有我们想要的东西。

你不能指望每个订阅者都记得做.do(() => this.feedService.refreshFeed()),而是在函数的doc注释中添加一个通知:“注意:返回的observable将刷新每个下一个信号的feed”或者那种东西。