Debouncing Events

There comes a time when several events fire in a row, and we don’t want to do something on every event, but rather, when the events stop firing for a specified period. In the typeahead case, we only want to make requests when the user stops typing. A function set up in this way is known as a debounced function. To create such a debounced function, you pass a function into debounce, which then returns another function that wraps the original function:

 let​ logPause = () => console.log(​'There was a pause in the typing'​);
 // This won't work, it will log on every keystroke
 // input.addEventListener('keydown', logPause);
 // Instead, we debounce logPause
 let​ logPauseDebounced = debounce(logPause);
 input.addEventListener(​'keydown'​, logPauseDebounced);

You can even write your own helper to wrap a regular function into a debounced function:

 function​ debounce(fn, delay=333) {
 let​ time;
 return​ ​function​ (...args) {
 if​ (time) {
  clearTimeout(time);
  }
  time = setTimeout(() => fn(...args), delay);
  }
 }
images/aside-icons/note.png Choosing a duration to wait in a debounce is more of an art than a science. A default of 333 ms usually works when waiting for a user to stop typing.

Debounce can be a bit confusing at first. Let’s put our debounce function through an example and watch what goes on:

 let​ f = debounce((num) => console.log(​'debounced! Arg:'​, num));
 
 // Call synchronously
 f(1);
 f(2);
 f(3);
 f(4);
 f(5);
 
 // Call several times in a short interval
 let​ i = 0;
 let​ interval = setInterval(() => {
  console.log(++i);
  f(i);
 }, 100);
 
 setTimeout(() => clearInterval(interval), 1000);

Throttling Events

Sometimes a debounce is more complicated than what you really need. The throttle operator acts as a time-based filter. After it allows a value through, it won’t allow a new value, until a preset amount of time has passed. All other values are thrown away. This can be useful when you connect to a noisy websocket that sends a lot more data than you need. For instance, you might be building a dashboard to keep the ops folks informed about all of their systems, and the monitoring backend sends updates on CPU usage several dozen times a second. DOM updates are slow, and that level of granularity isn’t helpful anyway. Here, we just update the page every half-second.

 cpuStatusWebsocket$
 .pipe(throttle(500))
 .subscribe(cpuVal => {
  cpuPercentElement.innerText = cpuVal;
 });

debounce wouldn’t work in this scenario; it would be left eternally waiting for a time when there is a pause in the updates around CPU usage. In the typeahead case, we do want to wait for a pause in activity, so we’ll use debounce instead of throttle.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.147.77