RxJS :(时间)缓冲区,在下一次发射后启动

时间:2016-10-02 16:36:08

标签: rxjs rxjs5

我想知道如何使用RxJs(4/5)正确实现这个?

-a-- -b----c----d-----------------------------------------------------------e------f---------------------
-5-sec after-"a"--> [abcd]---new 5 sec timer will start when "e" emited-----5 sec-after-"e"->[ef]-

我想这个:

.buffer(source$.throttleTime(5000).debounceTime(5000))

在rxjs 5中完成这项工作

4 个答案:

答案 0 :(得分:1)

你最好的拍摄是使用缓冲区。缓冲区具有关闭条件,并且您希望在引入新项目5秒后关闭条件。所以,假设你有一个源流,你想要的流将是:

source.buffer(source.throttle(5100).debounce(5000));

这是rxjs 4.我认为rxjs的缓冲区运算符略有不同,但想法是一样的。

说明: 节流阀确保对于5100 mSecs,您将只获得第一个“滴答”。去抖动将在5000 mSecs之后传播这个“滴答声”,因为之后没有其他“滴答声”。请注意,我选择5100 mSecs,因为时间并不总是完美的,如果你使用5000 mSecs,去抖可能会反复延迟,你会得到饥饿。无论如何,你的缓冲区不会丢失数据,只是将它分成大于5000 mSecs的块。

Rxjs 5有一个bufferToggle运算符,它可能看起来更好,但是,打开和关闭缓冲区这一事实可能会带来风险,并且会因时序问题而导致数据丢失。

答案 1 :(得分:0)

尝试了所有Rxjs 5缓冲区变体,特别是每隔n秒发出空缓冲区的bufferTime,我最终滚动了自己的bufferTimeLazy:

function bufferTimeLazy(timeout) {
  return Rx.Observable.create(subscriber => {
    let buffer = [], hdl;
    return this.subscribe(res => {
      buffer.push(res);
      if (hdl) return;

      hdl = setTimeout(() => {
        subscriber.next(buffer);
        buffer = [];
        hdl = null;
      }, timeout);

    }, err => subscriber.error(err), () => subscriber.complete());
  });
};

// add operator
Rx.Observable.prototype.bufferTimeLazy = bufferTimeLazy;

// example
const click$ = Rx.Observable.fromEvent(document, 'click');

click$.bufferTimeLazy(5000).subscribe(events => {
  console.log(`received ${events.length} events`);
});

实施例: https://jsbin.com/nizidat/6/edit?js,console,output

想法是在缓冲区中收集事件并在第一个事件发生后n秒发出缓冲区。一旦发出,空缓冲区并保持休眠状态,直到下一个事件到来。

如果您不想将操作符添加到Observable.prototype,只需调用函数:

bufferTimeLazy.bind(source$)(5000)

编辑: 好的,所以Rxjs 5并不是一件坏事:

var clicks = Rx.Observable.fromEvent(document, 'click').share();
var buffered = clicks.bufferWhen(() => clicks.delay(5000));
buffered.subscribe(x => console.log(`got ${x.length} events`));

达到同样的目标。注意share()以避免重复点击订阅 - YMMV。

答案 2 :(得分:0)

我正在使用RxJS 6,无法轻松找到5的文档。但是,这是一个奇妙的问题。这是我的结果,在real example中再现了Angular Material中的错误。

source$ = source$.pipe(buffer(source$.pipe(debounceTime(5000))));

答案 3 :(得分:0)

正如Trevor所提到的那样,在RXJS 6中没有官方的方法,但是显然您需要使用debounce + buffer才能获得该结果。

为了正确处理,在Typescript中并使用类型推断,我创建了一个名为 bufferDebounce 的自定义 OperatorFunction ,它使使用和理解起来更加容易运算符。

具有类型推断的代码段

type BufferDebounce = <T>(debounce: number) => OperatorFunction<T, T[]>;

const bufferDebounce: BufferDebounce = debounce => source =>
  new Observable(observer => 
    source.pipe(buffer(source.pipe(debounceTime(debounce)))).subscribe({
      next(x) {
        observer.next(x);
      },
      error(err) {
        observer.error(err);
      },
      complete() {
        observer.complete();
      },
  })
// [as many sources until no emit during 500ms]
source.pipe(bufferDebounce(500)).subscribe(console.log) 

您可以在下面的示例中进行尝试:https://stackblitz.com/edit/rxjs6-buffer-debounce

相关问题