Sending typing status with throttling and debouncing

09 May, 2022JavaScript, React

Tying status indicator is one of the few occurrences where both throttling and debouncing can be utilised, making it a perfect example to compare the differences between the two.

To explain throttle and debounce in short:

  • throttle: only fire the callback function once in a certain period.
  • debounce: only fire the callback function when it's not called for a certain period.

Tying status indicator requirements

  1. The client should send the typing event immediately when the user starts typing.
  2. The client should only send the typing event once every few seconds to avoid flooding the server and other receiving clients.
  3. The client should send the stopped event when the user stopped typing for a few seconds.
  4. The interval of sending the typing event is different from (usually longer than) the timeout of sending the stopped event.

Implementation

To achieve 1 and 2, we can simply apply a leading edge throttle to the callback function of sending the typing event:

const sendTyping = throttle(
  () => {
    ws.send('typing');
  },
  3000,
  { leading: true, trailing: false }
);

Similarly, to achieve 3 and 4, we apply a trailing edge debounce to the callback function of sending the stopped event:

const sendStopped = debounce(
  () => {
    sendTyping.cancel();
    ws.send('stopped');
  },
  1000,
  { leading: false, trailing: true }
);

Notice on line #3 we need to cancel the existing throttled sendTyping, to avoid sending duplicated stopped event. In case the throttle interval is more than 2 times of the debounce timeout, and the user happens to register more than one inputs within the throttle intervals:

And finally we can apply both sendTyping and sendStopped to the input component. Here is an React example, but you need to wrap the sendTyping and sendStopped in useCallback hooks (refer to the Codesandbox demo below for the complete source code).

<input
  onInput={() => {
    sendTyping();
    sendStopped();
  }}
/>

Demo


Powered by Gatsby. Theme inspired by end2end.

© 2014-2022. Made withby mdluo.