Hone logo
Hone
Problems

Implementing Debounce in Angular

Debouncing is a crucial technique for optimizing performance in Angular applications, particularly when dealing with user input events like typing in a search bar or resizing a window. This challenge asks you to implement a reusable debounced function within an Angular service, preventing excessive calls to an underlying function until a period of inactivity has passed. This will help avoid unnecessary API calls or computationally expensive operations.

Problem Description

You need to create an Angular service that provides a debounced function. This function should accept a callback function and a delay (in milliseconds) as arguments. When the debounced function is called, it should suppress subsequent calls until delay milliseconds have passed without another call. Only then should the original callback function be executed. The service should be reusable across different components.

Key Requirements:

  • Reusable Service: The debouncing logic should be encapsulated within an Angular service.
  • Debounced Function: The service should expose a function that, when called, returns a debounced version of the provided callback.
  • Delay Parameter: The debounced function should accept a delay parameter (in milliseconds) to control the debounce interval.
  • Callback Execution: The original callback function should only be executed after the specified delay has elapsed without any further calls to the debounced function.
  • this Context: The callback function should be executed with the correct this context (the context it had when the debounced function was initially called).
  • Argument Passing: Arguments passed to the debounced function should be correctly passed to the original callback function when it is eventually executed.

Expected Behavior:

  • Calling the debounced function multiple times within the delay period should not trigger the callback.
  • Only after the delay period has passed without any further calls should the callback be executed.
  • The callback should be executed with the correct this context and arguments.

Edge Cases to Consider:

  • Zero Delay: What should happen if the delay is set to 0? (Consider whether it should execute immediately or not).
  • Negative Delay: Handle invalid delay values (negative numbers). Throw an error or default to a reasonable delay.
  • Callback is Null/Undefined: Handle cases where the callback function is null or undefined.
  • Multiple Calls in Quick Succession: Ensure that the last call within the debounce window triggers the execution after the delay.

Examples

Example 1:

Input:
  callback: (message: string) => console.log(message);
  delay: 500
  Calls: debouncedCallback("Hello"), debouncedCallback("World"), debouncedCallback("!")
  (After 600ms) debouncedCallback("Goodbye")
Output:
  console.log("Goodbye")  // Only "Goodbye" should be logged after 600ms.  "Hello", "World", and "!" are ignored.
Explanation:
The callback is only executed after 600ms (500ms delay + 100ms inactivity) because the calls were made within the 500ms window.

Example 2:

Input:
  callback: () => alert("Debounce triggered!");
  delay: 200
  Calls: debouncedCallback(), debouncedCallback(), debouncedCallback()
  (After 300ms) debouncedCallback()
Output:
  alert("Debounce triggered!") // The alert should only appear after 300ms.
Explanation:
The calls within the 200ms window are ignored, and the final call after 300ms triggers the callback.

Example 3: (Edge Case - Zero Delay)

Input:
  callback: (num: number) => console.log("Number:", num);
  delay: 0
  Calls: debouncedCallback(1), debouncedCallback(2), debouncedCallback(3)
Output:
  console.log("Number:", 3) // The last call (3) should be executed immediately.
Explanation:
With a zero delay, the callback should execute immediately on the last call.

Constraints

  • The service should be written in TypeScript and compatible with Angular.
  • The delay parameter must be a non-negative number. If a negative number is provided, throw an error.
  • The service should be designed to be efficient and avoid unnecessary computations.
  • The debounced function should be able to handle any number of arguments passed to it.
  • The service should not introduce any external dependencies beyond Angular itself.

Notes

  • Consider using setTimeout or setInterval to implement the debouncing logic. setTimeout is generally preferred for this use case.
  • Think about how to preserve the this context and arguments of the original callback function. bind can be helpful here.
  • Focus on creating a clean, reusable, and well-documented service.
  • Test your implementation thoroughly with various scenarios, including edge cases.
  • Remember to handle the case where the callback function is null or undefined gracefully.
Loading editor...
typescript