Docs

18.5-Timers-and-Scheduling

11.5 Timers and Scheduling

Overview

JavaScript provides several mechanisms for scheduling code execution: setTimeout, setInterval, requestAnimationFrame, and requestIdleCallback. Understanding these is essential for creating responsive and performant applications.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Timer Methods Overview                        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                  β”‚
β”‚   setTimeout(fn, delay)                                          β”‚
β”‚   ─────────────────────                                         β”‚
β”‚   Execute ONCE after delay (milliseconds)                        β”‚
β”‚                                                                  β”‚
β”‚   Time ─────────────────────────────────────▢                   β”‚
β”‚         |←── delay ──→|                                         β”‚
β”‚         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                         β”‚
β”‚         β”‚   waiting   β”‚ β†’ fn() called                           β”‚
β”‚         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                         β”‚
β”‚                                                                  β”‚
β”‚   setInterval(fn, interval)                                      β”‚
β”‚   ─────────────────────────                                     β”‚
β”‚   Execute REPEATEDLY at interval                                 β”‚
β”‚                                                                  β”‚
β”‚   Time ─────────────────────────────────────▢                   β”‚
β”‚         |←─ int ─→|←─ int ─→|←─ int ─→|                         β”‚
β”‚            fn()      fn()      fn()                              β”‚
β”‚                                                                  β”‚
β”‚   requestAnimationFrame(fn)                                      β”‚
β”‚   ─────────────────────────                                     β”‚
β”‚   Execute before next repaint (~60fps = ~16.67ms)                β”‚
β”‚                                                                  β”‚
β”‚   requestIdleCallback(fn)                                        β”‚
β”‚   ───────────────────────                                       β”‚
β”‚   Execute when browser is idle                                   β”‚
β”‚                                                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

setTimeout

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                       setTimeout                                  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                  β”‚
β”‚   Syntax:                                                        β”‚
β”‚   ───────                                                       β”‚
β”‚   const timerId = setTimeout(callback, delay, ...args)           β”‚
β”‚                                                                  β”‚
β”‚   β€’ callback: Function to execute                                β”‚
β”‚   β€’ delay: Time in milliseconds (default: 0)                     β”‚
β”‚   β€’ args: Arguments passed to callback                           β”‚
β”‚   β€’ Returns: Timer ID for cancellation                           β”‚
β”‚                                                                  β”‚
β”‚   Cancellation:                                                  β”‚
β”‚   ─────────────                                                 β”‚
β”‚   clearTimeout(timerId)                                          β”‚
β”‚                                                                  β”‚
β”‚   Examples:                                                      β”‚
β”‚   ─────────                                                     β”‚
β”‚   // Basic usage                                                 β”‚
β”‚   setTimeout(() => console.log('Hello'), 1000);                  β”‚
β”‚                                                                  β”‚
β”‚   // With arguments                                              β”‚
β”‚   setTimeout((name) => console.log(`Hi ${name}`), 1000, 'John'); β”‚
β”‚                                                                  β”‚
β”‚   // Cancel before execution                                     β”‚
β”‚   const id = setTimeout(() => console.log('Never'), 5000);       β”‚
β”‚   clearTimeout(id);                                              β”‚
β”‚                                                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

setInterval

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                       setInterval                                 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                  β”‚
β”‚   Syntax:                                                        β”‚
β”‚   ───────                                                       β”‚
β”‚   const intervalId = setInterval(callback, interval, ...args)    β”‚
β”‚                                                                  β”‚
β”‚   Cancellation:                                                  β”‚
β”‚   ─────────────                                                 β”‚
β”‚   clearInterval(intervalId)                                      β”‚
β”‚                                                                  β”‚
β”‚   Example:                                                       β”‚
β”‚   ─────────                                                     β”‚
β”‚   let count = 0;                                                 β”‚
β”‚   const id = setInterval(() => {                                 β”‚
β”‚       count++;                                                   β”‚
β”‚       console.log(`Count: ${count}`);                            β”‚
β”‚       if (count >= 5) clearInterval(id);                         β”‚
β”‚   }, 1000);                                                      β”‚
β”‚                                                                  β”‚
β”‚   ⚠️ Warning: Interval drift                                    β”‚
β”‚   ────────────────────────                                      β”‚
β”‚   If callback takes longer than interval,                        β”‚
β”‚   calls can stack up or be delayed.                              β”‚
β”‚                                                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

setTimeout with 0 Delay

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  Zero Delay setTimeout                            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                  β”‚
β”‚   setTimeout(fn, 0) doesn't run immediately!                     β”‚
β”‚                                                                  β”‚
β”‚   console.log('1');                                              β”‚
β”‚   setTimeout(() => console.log('2'), 0);                         β”‚
β”‚   console.log('3');                                              β”‚
β”‚                                                                  β”‚
β”‚   Output: 1, 3, 2                                                β”‚
β”‚                                                                  β”‚
β”‚   Why? Event Loop:                                               β”‚
β”‚   ─────────────────                                             β”‚
β”‚   1. Synchronous code runs first (Call Stack)                    β”‚
β”‚   2. setTimeout callback goes to Task Queue                      β”‚
β”‚   3. Event Loop picks up callback after stack is empty           β”‚
β”‚                                                                  β”‚
β”‚   Minimum delay is ~4ms in browsers (after 5 nested calls)       β”‚
β”‚                                                                  β”‚
β”‚   Use Cases:                                                     β”‚
β”‚   ──────────                                                    β”‚
β”‚   β€’ Break up long-running tasks                                  β”‚
β”‚   β€’ Allow DOM updates to render                                  β”‚
β”‚   β€’ Defer execution to end of event loop tick                    β”‚
β”‚                                                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

requestAnimationFrame

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  requestAnimationFrame                            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                  β”‚
β”‚   Syntax:                                                        β”‚
β”‚   ───────                                                       β”‚
β”‚   const frameId = requestAnimationFrame(callback)                β”‚
β”‚   cancelAnimationFrame(frameId)                                  β”‚
β”‚                                                                  β”‚
β”‚   Callback receives: DOMHighResTimeStamp (ms since page load)    β”‚
β”‚                                                                  β”‚
β”‚   Why use it?                                                    β”‚
β”‚   ────────────                                                  β”‚
β”‚   βœ“ Synced with display refresh rate (usually 60fps)            β”‚
β”‚   βœ“ Paused in background tabs (saves battery/CPU)               β”‚
β”‚   βœ“ Optimized by browser for smooth animations                   β”‚
β”‚   βœ“ More accurate than setInterval for animations                β”‚
β”‚                                                                  β”‚
β”‚   Animation Loop Pattern:                                        β”‚
β”‚   ───────────────────────                                       β”‚
β”‚   function animate(timestamp) {                                  β”‚
β”‚       // Update animation state                                  β”‚
β”‚       element.style.left = `${x}px`;                             β”‚
β”‚                                                                  β”‚
β”‚       // Continue animation                                      β”‚
β”‚       requestAnimationFrame(animate);                            β”‚
β”‚   }                                                              β”‚
β”‚   requestAnimationFrame(animate);                                β”‚
β”‚                                                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

requestIdleCallback

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   requestIdleCallback                             β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                  β”‚
β”‚   Execute code when browser is idle (not critical work)          β”‚
β”‚                                                                  β”‚
β”‚   Syntax:                                                        β”‚
β”‚   ───────                                                       β”‚
β”‚   requestIdleCallback(callback, { timeout: 2000 })               β”‚
β”‚   cancelIdleCallback(id)                                         β”‚
β”‚                                                                  β”‚
β”‚   Callback receives IdleDeadline object:                         β”‚
β”‚   ─────────────────────────────────────                         β”‚
β”‚   deadline.didTimeout    β†’ true if timeout was reached           β”‚
β”‚   deadline.timeRemaining() β†’ ms left in idle period              β”‚
β”‚                                                                  β”‚
β”‚   Example:                                                       β”‚
β”‚   ─────────                                                     β”‚
β”‚   requestIdleCallback((deadline) => {                            β”‚
β”‚       while (deadline.timeRemaining() > 0 && tasks.length) {     β”‚
β”‚           const task = tasks.shift();                            β”‚
β”‚           processTask(task);                                     β”‚
β”‚       }                                                          β”‚
β”‚                                                                  β”‚
β”‚       if (tasks.length > 0) {                                    β”‚
β”‚           requestIdleCallback(processTasks);                     β”‚
β”‚       }                                                          β”‚
β”‚   }, { timeout: 1000 });                                         β”‚
β”‚                                                                  β”‚
β”‚   ⚠️ Not supported in Safari - use polyfill or fallback         β”‚
β”‚                                                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Debounce

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        Debounce                                   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                  β”‚
β”‚   Wait for pause in events before executing                      β”‚
β”‚                                                                  β”‚
β”‚   Events:  ─x─x─x─x─x─────────────x─x─x─────────                β”‚
β”‚                      |←─ wait ─→|       |← waitβ†’|               β”‚
β”‚   Calls:            ─────────────fn()───────────fn()            β”‚
β”‚                                                                  β”‚
β”‚   Use Cases:                                                     β”‚
β”‚   ──────────                                                    β”‚
β”‚   β€’ Search input (wait for user to stop typing)                  β”‚
β”‚   β€’ Window resize handling                                       β”‚
β”‚   β€’ Button click protection                                      β”‚
β”‚                                                                  β”‚
β”‚   Implementation:                                                β”‚
β”‚   ───────────────                                               β”‚
β”‚   function debounce(fn, delay) {                                 β”‚
β”‚       let timeoutId;                                             β”‚
β”‚       return function(...args) {                                 β”‚
β”‚           clearTimeout(timeoutId);                               β”‚
β”‚           timeoutId = setTimeout(() => fn.apply(this, args),     β”‚
β”‚                                   delay);                        β”‚
β”‚       };                                                         β”‚
β”‚   }                                                              β”‚
β”‚                                                                  β”‚
β”‚   Usage:                                                         β”‚
β”‚   ──────                                                        β”‚
β”‚   const debouncedSearch = debounce(search, 300);                 β”‚
β”‚   input.addEventListener('input', debouncedSearch);              β”‚
β”‚                                                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Throttle

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        Throttle                                   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                  β”‚
β”‚   Execute at most once per time period                           β”‚
β”‚                                                                  β”‚
β”‚   Events:  ─x─x─x─x─x─x─x─x─x─x─x─x─x─                          β”‚
β”‚            |←─ limit ─→|←─ limit ─→|                             β”‚
β”‚   Calls:   fn()────────fn()────────fn()                          β”‚
β”‚                                                                  β”‚
β”‚   Use Cases:                                                     β”‚
β”‚   ──────────                                                    β”‚
β”‚   β€’ Scroll event handling                                        β”‚
β”‚   β€’ Mouse move tracking                                          β”‚
β”‚   β€’ API rate limiting                                            β”‚
β”‚   β€’ Game input handling                                          β”‚
β”‚                                                                  β”‚
β”‚   Implementation:                                                β”‚
β”‚   ───────────────                                               β”‚
β”‚   function throttle(fn, limit) {                                 β”‚
β”‚       let waiting = false;                                       β”‚
β”‚       return function(...args) {                                 β”‚
β”‚           if (waiting) return;                                   β”‚
β”‚           fn.apply(this, args);                                  β”‚
β”‚           waiting = true;                                        β”‚
β”‚           setTimeout(() => waiting = false, limit);              β”‚
β”‚       };                                                         β”‚
β”‚   }                                                              β”‚
β”‚                                                                  β”‚
β”‚   Usage:                                                         β”‚
β”‚   ──────                                                        β”‚
β”‚   const throttledScroll = throttle(handleScroll, 100);           β”‚
β”‚   window.addEventListener('scroll', throttledScroll);            β”‚
β”‚                                                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Debounce vs Throttle

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  Debounce vs Throttle                             β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                  β”‚
β”‚                   Debounce              Throttle                 β”‚
β”‚   ─────────────────────────────────────────────────────────     β”‚
β”‚   When         After pause              At regular intervals     β”‚
β”‚   Guarantee    1 call after events      Max 1 call per period   β”‚
β”‚   Delay        From last event          From first event         β”‚
β”‚                                                                  β”‚
β”‚   Example Timeline (300ms):                                      β”‚
β”‚   ──────────────────────────                                    β”‚
β”‚   Events:      100  200  300  400  500 ─────── 1000             β”‚
β”‚   Debounce:    ─────────────────────────── 800 (calls once)     β”‚
β”‚   Throttle:    100 ──── 400 ──── 700 ──── 1000 (calls 4x)       β”‚
β”‚                                                                  β”‚
β”‚   Choose Debounce:                                               β”‚
β”‚   ────────────────                                              β”‚
β”‚   β€’ Final value matters (search, resize)                         β”‚
β”‚   β€’ Want to wait for "settling"                                  β”‚
β”‚   β€’ Reducing API calls                                           β”‚
β”‚                                                                  β”‚
β”‚   Choose Throttle:                                               β”‚
β”‚   ────────────────                                              β”‚
β”‚   β€’ Regular updates needed (scroll position)                     β”‚
β”‚   β€’ Real-time feedback (game input)                              β”‚
β”‚   β€’ Rate limiting                                                β”‚
β”‚                                                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Timer Accuracy

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Timer Accuracy                                 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                  β”‚
β”‚   Timers are NOT guaranteed to be precise!                       β”‚
β”‚                                                                  β”‚
β”‚   Factors affecting accuracy:                                    β”‚
β”‚   ───────────────────────────                                   β”‚
β”‚   β€’ Minimum delay (~4ms in browsers)                             β”‚
β”‚   β€’ Browser throttling in background tabs                        β”‚
β”‚   β€’ System load and available resources                          β”‚
β”‚   β€’ Other JavaScript execution blocking                          β”‚
β”‚   β€’ Event loop congestion                                        β”‚
β”‚                                                                  β”‚
β”‚   Background Tab Throttling:                                     β”‚
β”‚   ──────────────────────────                                    β”‚
β”‚   β€’ setTimeout/setInterval: Limited to 1 call/second             β”‚
β”‚   β€’ requestAnimationFrame: Paused completely                     β”‚
β”‚   β€’ requestIdleCallback: May not run                             β”‚
β”‚                                                                  β”‚
β”‚   For precise timing:                                            β”‚
β”‚   ───────────────────                                           β”‚
β”‚   β€’ Use performance.now() for measurements                       β”‚
β”‚   β€’ Web Workers for background processing                        β”‚
β”‚   β€’ Web Audio API for audio timing                               β”‚
β”‚                                                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Async Sleep / Delay

// Promise-based delay
function delay(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

// Usage with async/await
async function example() {
  console.log('Start');
  await delay(2000);
  console.log('After 2 seconds');
}

// Cancellable delay
function cancellableDelay(ms) {
  let timeoutId;
  const promise = new Promise((resolve, reject) => {
    timeoutId = setTimeout(resolve, ms);
  });

  return {
    promise,
    cancel: () => clearTimeout(timeoutId),
  };
}

Common Patterns

Polling

async function poll(fn, interval, maxAttempts = Infinity) {
  let attempts = 0;

  while (attempts < maxAttempts) {
    const result = await fn();
    if (result) return result;

    attempts++;
    await delay(interval);
  }

  throw new Error('Polling timeout');
}

// Usage
await poll(
  async () => {
    const status = await checkStatus();
    return status === 'complete' ? status : null;
  },
  1000,
  30
);

Retry with Backoff

async function retryWithBackoff(fn, maxRetries = 3, baseDelay = 1000) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      await delay(baseDelay * Math.pow(2, i));
    }
  }
}

Best Practices

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     Best Practices                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                  β”‚
β”‚   1. Always store timer IDs                                      β”‚
β”‚      const id = setTimeout(...);                                 β”‚
β”‚      // Later: clearTimeout(id);                                 β”‚
β”‚                                                                  β”‚
β”‚   2. Clean up on component unmount                               β”‚
β”‚      useEffect(() => {                                           β”‚
β”‚          const id = setInterval(...);                            β”‚
β”‚          return () => clearInterval(id);                         β”‚
β”‚      }, []);                                                     β”‚
β”‚                                                                  β”‚
β”‚   3. Use requestAnimationFrame for visual updates                β”‚
β”‚      // Not: setInterval(() => moveElement(), 16);               β”‚
β”‚      // Use: requestAnimationFrame(animate);                     β”‚
β”‚                                                                  β”‚
β”‚   4. Debounce/throttle event handlers                            β”‚
β”‚      window.addEventListener('resize', debounce(handle, 250));   β”‚
β”‚                                                                  β”‚
β”‚   5. Use requestIdleCallback for non-critical work               β”‚
β”‚      requestIdleCallback(() => trackAnalytics());                β”‚
β”‚                                                                  β”‚
β”‚   6. Consider Web Workers for heavy computation                  β”‚
β”‚      // Timers in workers aren't throttled                       β”‚
β”‚                                                                  β”‚
β”‚   7. Use performance.now() for accurate timing                   β”‚
β”‚      const start = performance.now();                            β”‚
β”‚      // ... work ...                                             β”‚
β”‚      const elapsed = performance.now() - start;                  β”‚
β”‚                                                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Browser Compatibility

FeatureChromeFirefoxSafariEdge
setTimeout1+1+1+12+
setInterval1+1+1+12+
requestAnimationFrame24+23+6.1+12+
requestIdleCallback47+55+❌79+
performance.now()24+15+8+12+

Key Takeaways

  1. β€’setTimeout - One-time delayed execution
  2. β€’setInterval - Repeated execution at intervals
  3. β€’requestAnimationFrame - Smooth animations synced with display
  4. β€’requestIdleCallback - Non-critical background tasks
  5. β€’Debounce - Wait for pause before executing
  6. β€’Throttle - Limit execution frequency
  7. β€’Clean up timers - Always cancel when no longer needed
  8. β€’Timers aren't precise - Account for delays and throttling
.5 Timers And Scheduling - JavaScript Tutorial | DeepML