Manipulating Time (Follow Along)

Let's head over to our playground and—erm—play around for a bit, shall we?

We're mostly just trying to get familiar with the delay, throttleTime, and debounceTime operators here. So, let's get to experimenting, shall we?

We'll start by putting a simple delay on the button and seeing what happens.

const buttonClicks$ = fromEvent(button, 'click').pipe(delay(2000));

This, of course, creates a fun problem. Even though we're the ones that put that delay on the button, it's tempting to want to click it a bunch of times because we don't think it's working because of that delay.

You'll also notice that delay isn't necessarily spacing them out. If we rage click, they all come in roughly the same time, just two seconds in the future.

So, what would this look like if we said throttled that button a bit?

const buttonClicks$ = fromEvent(button, 'click').pipe(
  throttleTime(2000),
  delay(2000),
);

So, now we can go to town on that button and we'll see that only one message appears. (If you see more than one, you might have to reload the page to clear out those old event listeners.)

This effect is more pronounced if we remove the delay completely and just go at the button with reckless abandonment.

const buttonClicks$ = fromEvent(button, 'click').pipe(
  throttleTime(2000),
  // delay(2000)
);

You can keep clicking, but a new message will only show up every two seconds.

As we discussed, debounceTime works a bit differently. With debounceTime we ignore emitted values until there is a period of silence and then we take the last one and deal with it.

const buttonClicks$ = fromEvent(button, 'click').pipe(debounceTime(1000));

I can click that button to my heart's content, but a new notification will only be displayed after I chill out for a second.

Throttling and Debouncing with Other Observables

If you peeked at the API documentation. You might have also seen that there are just plain ol' throttle and debounce operators as well. These work a little bit differently. They rely on subscribing to some other observable.

Instead on relying on a given amount of time, this one will throttle or debounce until the dependant observable emits a value. Let's try something like this.

const panicButtonClicks$ = fromEvent(panicButton, 'click');
const buttonClicks$ = fromEvent(button, 'click').pipe(
  debounce(() => panicButtonClicks$),
);

I can keep clicking, but nothing will happen until I click the panic button. throttle works in the opposite fashion. The first notification will be displayed, but subsequent ones will not be until the panic button is pressed again.

const panicButtonClicks$ = fromEvent(panicButton, 'click');
const buttonClicks$ = fromEvent(button, 'click').pipe(
  throttle(() => panicButtonClicks$),
);

Mimicking debounceTime and throttleTime

We know the folloing two things to be true:

So, it stands to reason, that we can recreate the behavior of throttleTime and debounceTime.

const buttonClicks$ = fromEvent(button, 'click').pipe(
  throttle(() => interval(2000)),
);