debounce()
Debounce a function to only be called after wait milliseconds of inactivity.
Implementation
The debounced function will be called with the last provided arguments after wait milliseconds have passed since the last call. This is useful for preventing excessive calls to a function that is expensive or has side effects. The debounced function is thread-safe and will not raise exceptions if the original function raises an exception. Args: func: The function to debounce wait: The delay in milliseconds Returns: A debounced function
Example
def api_call():
return "Called!"
debounced = debounce(api_call, 100)
# Function will execute after 100ms of inactivity
Expected output: Function that executes 200ms after the last call
Source Code
def debounce(func: Callable, wait: int) -> Callable:
wait_seconds = wait / 1000.0
timer = None
lock = threading.RLock() # Reentrant lock for safety
max_pending_timers = 10 # Prevent DoS
pending_count = [0]
def debounced(*args, **kwargs):
nonlocal timer
# DoS protection
if pending_count[0] > max_pending_timers:
return # Silently drop excessive calls
with lock: # Atomic check-and-set
if timer is not None:
timer.cancel()
pending_count[0] = max(0, pending_count[0] - 1)
def safe_call():
try:
with lock:
pending_count[0] = max(0, pending_count[0] - 1)
func(*args, **kwargs)
except Exception:
# Prevent exceptions from breaking debounce state
with lock:
pending_count[0] = max(0, pending_count[0] - 1)
timer = threading.Timer(wait_seconds, safe_call)
timer.daemon = True
pending_count[0] += 1
timer.start()
return debounced