8

Is there an operator in RxJS that debounces without delaying the "first event in a burst", but delaying (and always emitting) the "last event in a burst"?

Something like this:

---a----b-c-d-----e-f---

after awesome-debounce(2 dashes) becomes:

---a----b------d--e----f

while a normal debounce would be:

-----a---------d-------f

It's kind of a mix between throttle and debounce...

Roman
  • 5,888
  • 26
  • 47

2 Answers2

7

Hmmm, this is the easiest solution I can think of. The interesting part for you is the awesomeDebounce() function that creates the sub-chain.

It basically just combines throttle() and debounceTime() operators:

const Rx = require('rxjs');
const chai = require('chai');

let scheduler = new Rx.TestScheduler((actual, expected) => {
  chai.assert.deepEqual(actual, expected);
  console.log(actual);
});

function awesomeDebounce(source, timeWindow = 1000, scheduler = Rx.Scheduler.async) {
  let shared = source.share();
  let notification = shared
      .switchMap(val => Rx.Observable.of(val).delay(timeWindow, scheduler))
      .publish();

  notification.connect();

  return shared
    .throttle(() => notification)
    .merge(shared.debounceTime(timeWindow, scheduler))
    .distinctUntilChanged();
}

let sourceMarbles =   '---a----b-c-d-----e-f---';
let expectedMarbles = '---a----b------d--e----f';

// Create the test Observable
let observable = scheduler
  .createHotObservable(sourceMarbles)
  .let(source => awesomeDebounce(source, 30, scheduler));

scheduler.expectObservable(observable).toBe(expectedMarbles);
scheduler.flush();

The inner notification Observable is used only for the throttle() operator so I can reset its timer manually when I need. I also had to turn this Observable into "hot" to be independent on the internal subscriptions from throttle().

Frederik Struck-Schøning
  • 12,981
  • 8
  • 59
  • 68
martin
  • 93,354
  • 25
  • 191
  • 226
  • 1
    I'm going to award this answer a bounty for the nice demonstration and inclusion of marble tests. Just pending the 24 hour wait – Ingo Bürk Feb 23 '18 at 19:46
-1

That's indeed useful debounce type for many situations. Use merge, throttleTime and debounceTime in a next way:

Rx.Observable.merge(source.throttleTime(1000), source.debounceTime(2000))

Full example is here http://jsbin.com/godocuqiwo/edit?js,console

Note: it will emit not only first and last value in debounce interval but also values produced by throttle (which is usually expected and needed, as for scroll debouncing for example).

Frederik Struck-Schøning
  • 12,981
  • 8
  • 59
  • 68
Vladimir Tolstikov
  • 2,463
  • 21
  • 14