Challenge 1: Debounce a Resize Handler — Possible Solution ==================================================================== function debounce(fn, delay) { let timeoutId; return (...args) => { clearTimeout(timeoutId); timeoutId = setTimeout(() => fn(...args), delay); }; } const debouncedRecalculate = debounce(recalculateLayout, 200); window.addEventListener("resize", debouncedRecalculate); WHY THIS WORKS -------------- - debounce() returns a NEW function that wraps recalculateLayout — every time this wrapped function is called (once per resize event), it FIRST clears any previously scheduled timeout, then schedules a fresh one 200ms out. This means as long as resize events keep firing faster than every 200ms, the actual call to recalculateLayout() keeps getting pushed back and never happens. - Only once the resize events genuinely STOP firing for a full 200ms — the user has actually finished dragging the window edge — does the most recently scheduled timeout finally survive long enough to fire, calling recalculateLayout() exactly once for that entire resize gesture, rather than dozens of times during it. - This matches the chapter's own description of debounce as suited to "final state" work: recalculating a layout mid-resize (before the user has settled on a final size) would be wasted work, recomputed and thrown away repeatedly — debounce ensures the expensive recalculation happens exactly once, using the FINAL size the user actually settles on. - window.addEventListener("resize", debouncedRecalculate) attaches the DEBOUNCED wrapper as the actual event listener — not the raw recalculateLayout function directly — which is the key detail that makes this whole pattern work; the raw function is never registered as the listener itself.