使用超时作为反应流实现轮询器的最佳方法是什么。

时间:2018-05-08 17:54:13

标签: rxjs rx-java reactive-programming system.reactive rx-java2

使用超时对轮询器进行建模的最佳方法是什么?某个条件导致提前退出为“反应流”?

e.g。

如果我有一个可观测值,每秒产生一个递减的正整数序列

9,8,7,6,5,4,3,2,1,0

编写消费者的最佳方法是在5秒后获取最新的单个事件,如果生成的时间超过超时,则为“0”事件。

这是我现在的代码:( Java中的示例)

    int intialValue = 10;

    AtomicInteger counter = new AtomicInteger(intialValue);
    Integer val = Observable.interval(1, TimeUnit.SECONDS)
                            .map(tick -> counter.decrementAndGet())
                            .takeUntil(it -> it == 0)
                            .takeUntil(Observable.timer(5, TimeUnit.SECONDS))
                            .lastElement()
                            .blockingGet();

    System.out.println(val);

如果initialValue = 10,我希望打印6。如果initialValue = 2,我希望在5秒超时到期之前打印0。

如果有更好的方法,我很感兴趣。

1 个答案:

答案 0 :(得分:0)

我认为没有比你做得更好的方式。您必须具备以下条件:

  • 要发出的间隔(interval
  • 用于递减和存储最后一个值(scan
  • 的聚合器
  • 值(takeWhile
  • 的终止条件
  • 终止条件(takeUntil(timer(...))
  • 完成时获取最后一个值(last

每个人都由一名运营商代表。你不可能做很多事情来解决这个问题。我使用了一些不同的运算符(scan用于聚合,takeWhile用于终止值)但是它的运算符数相同。



const { interval, timer } = rxjs;
const { scan, takeWhile, takeUntil, last, tap } = rxjs.operators;

function poll(start) {
  console.log('start', start);
  interval(1000).pipe(
    scan((x) => x - 1, start),
    takeWhile((x) => x >= 0),
    takeUntil(timer(5000)),
    tap((x) => { console.log('tap', x); }),
    last()
  ).subscribe(
    (x) => { console.log('next', x); },
    (e) => { console.log('error', e); },
    () => { console.log('complete'); }
  );
}

poll(10);
setTimeout(() => { poll(2); }, 6000);

<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.1.0/rxjs.umd.min.js"></script>
&#13;
&#13;
&#13;

我不清楚你希望它如何在边界上发挥作用。在你的例子中,你总是在发射之前递减,所以如果你的初始值是10,那么你发出9,8,7,6(4个值)。如果你想从10开始那么。您可以执行scan(..., start + 1),但这会在7结束,因为takeUntil(...)中的计时器与源间隔对齐,因此将排除6。如果要发出5个值,则可以执行takeUntil(timer(5001))。另外,如果您不想等一秒钟发出第一个值,那么您可以将startWith(start)放在scan(...)之后。或者您可以timer(0, 1000)使用scan(..., start + 1)代替源间隔。

另请注意,在生成无效值(takeWhile)之前,值(-1)的终止不会终止。所以它会在收到终止值(0)后持续一秒钟。似乎大多数终止运算符都以这种方式工作,如果它们终止于某些值,那么它们就不会让其他运算符通过。

您可以执行take(5)而不是takeUntil(timer(5000)),因为您知道如果适用于您的方案,它会在匹配的时间间隔内触发。由于计时器排队,这也可以解决排除最后一个值的问题。