Taro Logo

Debounce

Medium
a month ago

Given a function fn and a time in milliseconds t, return a debounced version of that function.

A debounced function is a function whose execution is delayed by t milliseconds and whose execution is cancelled if it is called again within that window of time. The debounced function should also receive the passed parameters.

For example, let's say t = 50ms, and the function was called at 30ms, 60ms, and 100ms.

The first 2 function calls would be cancelled, and the 3rd function call would be executed at 150ms.

Consider these examples:

Example 1: Input: t = 50 calls = [ {"t": 50, inputs: [1]}, {"t": 75, inputs: [2]} ] Output: [{ "t": 125, inputs: [2] }]

Example 2: Input: t = 20 calls = [ {"t": 50, inputs: [1]}, {"t": 100, inputs: [2]} ] Output: [{ "t": 70, inputs: [1] }, { "t": 120, inputs: [2] }]

Sample Answer
/**
 * @param {Function} fn
 * @param {number} t
 * @return {Function}
 */
var debounce = function(fn, t) {
  let timeoutId = null;
  return function(...args) {
    if (timeoutId) {
      clearTimeout(timeoutId);
    }
    timeoutId = setTimeout(() => {
      fn(...args);
      timeoutId = null; // Reset timeoutId after execution
    }, t);
  }
};

/**
 * const log = (...args) => console.log(args);
 * const dlog = debounce(log, 50);
 * setTimeout(() => dlog(1), 30);
 * setTimeout(() => dlog(2), 100);
 */

Explanation

  1. Initialization:

    • timeoutId: This variable will store the ID of the timeout. It's initialized to null because initially there's no pending timeout.
  2. Returned Debounced Function:

    • The debounce function returns a new function. This is the debounced version of the original function fn.
    • This returned function uses the closure to access and modify the timeoutId variable.
  3. Inside the Debounced Function:

    • clearTimeout(timeoutId): If there's an existing timeout (i.e., timeoutId is not null), it's cleared. This cancels the previously scheduled execution of fn.
    • setTimeout(...): A new timeout is set. This schedules the execution of fn after t milliseconds.
      • The setTimeout function returns an ID, which is stored in timeoutId. This ID is used to clear the timeout later if needed.
      • Inside the setTimeout callback:
        • fn(...args): The original function fn is called with the arguments passed to the debounced function.
        • timeoutId = null: The timeoutId is set to null after fn is executed. This indicates that there's no timeout pending currently.

Big O Runtime Analysis

The runtime complexity is O(1) for each call to the debounced function. clearTimeout and setTimeout are both constant-time operations.

Big O Space Usage Analysis

The space complexity is O(1) because we are only using a fixed number of variables (timeoutId).

Edge Cases

  1. t = 0: If t is 0, the function will be executed as soon as possible, but still debounced. If called multiple times quickly, only the last call will execute immediately.
  2. Multiple arguments: The debounced function correctly handles multiple arguments passed to the original function fn using the spread operator (...args).
  3. No calls: If the debounced function is never called, fn will never be executed. timeoutId will remain null.
  4. Calls finish: If calls are spaced far enough apart (greater than t milliseconds), each call will result in an execution of fn.