RxJS: debounce stream only if

I want to cancel the stream, but only if the original value is the same as before. How do I do this with RxJS 5?

I don't want to highlight the value if the value is the same and I selected it earlier during the specified time window. I should be able to use the value from stream - or compare function similar to distinctUntilChanged function.

+3


source to share


2 answers


I don't know how to do this without creating your own operator, because you need to maintain some kind of state (last seen value).

One way looks like this:

// I named this debounceDistinctUntilChanged but that might not be
// the best name. Name it whatever you think makes sense!

function debounceDistinctUntilChanged(delay) {
  const source$ = this;

  return new Observable(observer => {
    // Using an object as the default value
    // so that the first time we check it
    // if its the same its guaranteed to be false
    // because every object has a different identity.
    // Can't use null or undefined because source may
    // emit these!
    let lastSeen = {};

    return source$
      .debounce(value => {
        // If the last value has the same identity we'll
        // actually debounce
        if (value === lastSeen) {
          return Observable.timer(delay);
        } else {
          lastSeen = value;
          // This will complete() right away so we don't actually debounce/buffer
          // it at all
          return Observable.empty();
        }
      })
      .subscribe(observer);
  });
}

      

Now when you see an implementation that you may (or may not) find, it is different from your expectations. In fact, there are some details left in your description, for example if it should only be the last value that you keep during the time period of outages, or if it is set - mostly distinctUntilChanged

against distinct

. I assumed that later.

Anyway, hopefully this will give you a starting point and show you how easy it is to create custom operators. Built-in operators definitely don't provide a solution for everything there is, so any sufficiently advanced application will have to create its own (or do the urgent stuff internally without abstracting it, which is fine too).

Then you can use this operator by placing it in the Observable prototype:



Observable.prototype.debounceDistinctUntilChanged = debounceDistinctUntilChanged;

// later
source$
  .debounceDistinctUntilChanged(400)
  .subscribe(d => console.log(d));

      

Or using let

:

// later
source$
  .let(source$ => debounceDistinctUntilChanged.call($source, 400))
  .subscribe(d => console.log(d));

      


If you can, I recommend that you really understand what my code is doing so that you can easily create your own solutions in the future.

+1


source


It depends on what you are trying to do; I came across this question when I was trying to do something similar, mostly debouncing, but with different debounces for different object values.

After trying a solution from jayphelps, I couldn't get it to behave the way I wanted. After a lot of back and forth, it turns out there is a built-in easy way to do this: groupby.

const priceUpdates = [
  {bid: 10, id: 25},
  {bid: 20, id: 30},
  {bid: 11, id: 25},
  {bid: 21, id: 30},
  {bid: 25, id: 30}
];//emit each person
const source = Rx.Observable.from(priceUpdates);
//group by age
const example = source
  .groupBy(bid => bid.id)
  .mergeMap(group$ => group$.debounceTime(500))

const subscribe = example.subscribe(val => console.log(val));

      

Output:



[object Object] {
  bid: 11,
  id: 25
}
[object Object] {
  bid: 25,
  id: 30
}

      

Jsbin: http://jsbin.com/savahivege/edit?js,console

This code will group with the bet id and debut on this one, so only post the latest values ​​for each.

+1


source







All Articles