Search-as-you-type, and debounce
We have a gallery of pictures. Let's add search-as-you-type: the user types, and the grid immediately narrows to the matching pictures. Since we already downloaded the data, we filter client-side — no new requests to the server.
The filter is simple — case-insensitive matching on the title:
pictures.filter(p => p.title.toLowerCase().includes(query.toLowerCase()));
But there's a trap: when to filter. The naive way is on every keystroke:
searchInput.addEventListener('input', (e) => { filterAndRender(e.target.value); });
Typing "andromeda" fires that 9 times — re-rendering the whole grid each time. For a local search that's at least janky; and if the search went to the server (as it does in real projects), that would be 9 requests instead of one, per keystroke.
The fix — debounce. The idea: do nothing until the user stops typing. Technically — setTimeout and clearTimeout:
function debounce(fn, delay = 250) {
let timer;
return (...args) => {
clearTimeout(timer); // cancel the previously scheduled run
timer = setTimeout(() => fn(...args), delay); // schedule a new one after delay
};
}
Each keystroke cancels the previous pending run and schedules a new one. Only the last one fires — when nothing's been pressed for 250 ms. "andromeda" → one filter, not nine.