Debounce and throttle are wrapper functions that limit how often an event handler runs. Debounce waits for a pause in events before calling once; throttle guarantees at most one call per time window. Both are built from a closure and a timer.
Browsers emit some events far faster than an application can usefully respond to them. A user typing fires a keyup every 50 to 100 ms, scrolling fires dozens of events per second, and resizing a window fires continuously while the drag is in progress. Running a network request or a layout calculation on every one of those events wastes work and can make the page feel slower, not faster.
Debounce solves this by postponing the call until the events stop. Each new event cancels the previous timer and starts a fresh one, so the wrapped function only runs after a full quiet period of the configured length. Throttle takes the opposite stance: it lets the first event through immediately, then ignores everything else until a fixed window has elapsed, so the handler runs at a steady maximum rate while the stream continues.
Both are implemented with the same two ingredients. A closure holds state that must survive between calls, such as the current timeout id or an in-window flag, and setTimeout provides the clock. The wrapper returned by debounce or throttle is the only thing the caller sees, and it forwards the receiver and arguments to the real function with fn.apply so that method handlers and event arguments still work.
The choice between them is about which moment matters. If only the final state is useful, such as the finished search query or the settled window size, debounce is correct because intermediate calls would be thrown away. If the UI must track the stream while it happens, such as a scroll position indicator or a drag preview, throttle is correct because debounce would freeze until the user stopped.
Interview framing: define Debounce & Throttle in one sentence, then explain one concrete runtime behavior and one common pitfall with a short code example.