Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does throttleTime operator's config parameter work? (ThrottleConfig)

I have read the throttleTime documentation, but I don't get the operator fully.

I know how throttleTime(1000) works. After an event arrives it will skip all subsequent events for 1 second and then start this process again.

What I have trouble to understand is how exactly ThrottleConfig works, which is the third parameter of the operator.

throttleTime<T>(
  duration: number, 
  scheduler: SchedulerLike = async, 
  config: ThrottleConfig = defaultThrottleConfig): MonoTypeOperatorFunction<T>

How do leading and trailing properties change the functionality of the source Observable?

I have read many documentations but they don't clearly explain this.

So there are four options:

  1. { leading: true, trailing: false }:
    default option, after receiving event skips other events for specified duration and then repeat.
  2. { leading: false, trailing: true }:
    ???
  3. { leading: false, trailing: false }:
    Tested this and the Observable doesn't emit anything at all.
  4. { leading: true, trailing: true }:
    ???
like image 335
Goga Koreli Avatar asked Jul 16 '19 14:07

Goga Koreli


2 Answers

throttleTime will start a new throttle interval (a time period in which no items will be emitted) when it receives a new value and isn't already throttled. The length of this throttle interval is determined by the duration you supply.

With RxJS 7 a new throttle interval is also started when a trailing value is emitted at the end of a throttle interval.

leading and trailing specify whether an item should be emitted at the beginning or end of a throttle interval.

leading: Emit an item at the beginning of a new throttle interval.

trailing: Emit the last item received from the source at the end of a throttle interval.

Visualisation

RxJS 6 & 7 - trailing: false

throttleTime(12 ticks, { leading: true, trailing: false })

source_1:           --0--1-----2--3----4--5-6---7------------8-------9---------
throttle interval:  --[~~~~~~~~~~~]----[~~~~~~~~~~~]---------[~~~~~~~~~~~]-----
output_1:           --0----------------4---------------------8-----------------


source_2:           --0--------1------------------2--------------3---4---------
throttle interval:  --[~~~~~~~~~~~]---------------[~~~~~~~~~~~]--[~~~~~~~~~~~]-
output_2:           --0---------------------------2--------------3-------------
throttleTime(12 ticks, { leading: false, trailing: false })

source_1:           --0--1-----2--3----4--5-6---7------------8-------9---------
throttle interval:  --[~~~~~~~~~~~]----[~~~~~~~~~~~]---------[~~~~~~~~~~~]-----
output_1:           -----------------------------------------------------------


source_2:           --0--------1------------------2--------------3---4---------
throttle interval:  --[~~~~~~~~~~~]---------------[~~~~~~~~~~~]--[~~~~~~~~~~~]-
output_2:           -----------------------------------------------------------

RxJS 6 - trailing: true

throttleTime(12 ticks, { leading: true, trailing: true })

source_1:           --0--1-----2--3----4--5-6---7------------8-------9---------
throttle interval:  --[~~~~~~~~~~~]----[~~~~~~~~~~~]---------[~~~~~~~~~~~]-----
output_1:           --0-----------3----4-----------7---------8-----------9-----


source_2:           --0--------1------------------2--------------3---4---------
throttle interval:  --[~~~~~~~~~~~]---------------[~~~~~~~~~~~]--[~~~~~~~~~~~]-
output_2:           --0-----------1---------------2--------------3-----------4-
throttleTime(12 ticks, { leading: false, trailing: true })

source_1:           --0--1-----2--3----4--5-6---7------------8-------9---------
throttle interval:  --[~~~~~~~~~~~]----[~~~~~~~~~~~]---------[~~~~~~~~~~~]-----
output_1:           --------------3----------------7---------------------9-----


source_2:           --0--------1------------------2--------------3---4---------
throttle interval:  --[~~~~~~~~~~~]---------------[~~~~~~~~~~~]--[~~~~~~~~~~~]-
output_2:           --------------1---------------------------2--------------4-

RxJS 7 - trailing: true

throttleTime(12 ticks, { leading: true, trailing: true })

source_1:           --0--1-----2--3----4--5-6---7------------8-------9---------
throttle interval:  --[~~~~~~~~~~~I~~~~~~~~~~~I~~~~~~~~~~~I~~~~~~~~~~~I~~~~~~~~
output:             --0-----------3-----------6-----------7-----------9--------


source_2:           --0--------1------------------2--------------3---4---------
throttle interval:  --[~~~~~~~~~~~I~~~~~~~~~~~]---[~~~~~~~~~~~]--[~~~~~~~~~~~I~
output_2:           --0-----------1---------------2--------------3-----------4-
throttleTime(12 ticks, { leading: false, trailing: true })

source_1:           --0--1-----2--3----4--5-6---7------------8-------9---------
throttle interval:  --[~~~~~~~~~~~I~~~~~~~~~~~I~~~~~~~~~~~I~~~~~~~~~~~I~~~~~~~~
output:             --------------3-----------6-----------7-----------9--------


source_2:           --0--------1------------------2--------------3---4---------
throttle interval:  --[~~~~~~~~~~~I~~~~~~~~~~~]---[~~~~~~~~~~~I~~~~~~~~~~~]----
output_2:           --------------1---------------------------2-----------4----
like image 151
frido Avatar answered Sep 27 '22 20:09

frido


The expected output for { leading: true, trailing: true } has changed in rxjs 7: https://github.com/ReactiveX/rxjs/commit/ea84fc4dce84e32598701f79d9449be00a05352c

It will now ensure the spacing between throttles is always at least the throttled amount.

So the throttle interval will repeat immediately if there was a trailing emit. This makes the example from @frido change to something like this:

source:              --0--1-----2--3----4--5-6---7------------8-------9--------
throttle interval:   --[~~~~~~~~~~~x~~~~~~~~~~~x~~~~~~~~~~~x~~~~~~~~~~~x~~~~~~~
output:              --0-----------3-----------6-----------7-----------9-------

I have recreated the example from @frido with a valid test case below.

const testScheduler = new rxjs.testing.TestScheduler((actual, expected) => {
  const actualString = JSON.stringify(actual);
  const expectedString = JSON.stringify(expected)
  console.log(actualString)
  console.log(expectedString);
  console.log(expectedString === actualString);
});
testScheduler.run((helpers) => {
  const { cold, time, expectObservable, expectSubscriptions } = helpers;
  const e1 = cold(' --0--1-----2--3----4--5-6---7------------8-------9--------|');
  const expected = '--0-----------3-----------6-----------7-----------9-------|';
  const e1subs = '  ^---------------------------------------------------------!';
  const t = time('  ------------|'); // t = 12

  expectObservable(e1.pipe(
      rxjs.operators.throttleTime(t, null, { leading: true, trailing: true })
  )).toBe(expected);
  expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
<script src="https://unpkg.com/[email protected]/dist/bundles/rxjs.umd.js"></script>
like image 37
Sámal Rasmussen Avatar answered Sep 27 '22 20:09

Sámal Rasmussen