Debounce и throttle
↑ 2.1 JavaScript: продвинутый · ← Предыдущая · → Следующая
Зачем это на собесе
Классическая задача на замыкания и таймеры; реализуют «на доске».
Объяснение
| Debounce | Throttle | |
|---|---|---|
| Идея | вызвать после паузы в событиях | не чаще одного раза за интервал |
| Пример | поиск при вводе, автосохранение | скролл, resize, mousemove |
| Вызов | trailing (после паузы) | leading/trailing по периодам |
function debounce(fn, delay, { leading = false } = {}) {
let timer;
return function debounced(...args) {
const callNow = leading && !timer;
clearTimeout(timer);
timer = setTimeout(() => { timer = null; if (!leading) fn.apply(this, args); }, delay);
if (callNow) fn.apply(this, args);
};
}
function throttle(fn, interval) {
let last = 0, timer, lastArgs;
return function throttled(...args) {
const now = Date.now(), remaining = interval - (now - last);
lastArgs = args;
if (remaining <= 0) { clearTimeout(timer); timer = null; last = now; fn.apply(this, args); }
else if (!timer) timer = setTimeout(() => { last = Date.now(); timer = null; fn.apply(this, lastArgs); }, remaining);
};
}input.addEventListener("input", debounce((e) => search(e.target.value), 300));
window.addEventListener("scroll", throttle(updateHeader, 100), { passive: true });Во Vue: watchDebounced, useDebounceFn, useThrottleFn (VueUse); для запросов — отмена предыдущих (AbortController), в Vue Query — keepPreviousData.
Альтернативы: requestAnimationFrame для визуальных обновлений, IntersectionObserver вместо scroll-слушателей.
Нюансы и подводные камни
- Debounce на общем экземпляре создаётся один раз (не внутри функции рендера) — иначе таймеры разные.
- Отмена при размонтировании компонента:
debounced.cancel(). - Устаревшие ответы: медленный запрос может прийти после нового — используйте отмену или сопоставление токенов.
- Слишком большая задержка портит UX.
Практика
- Реализуйте
debounceсcancelиflush,throttleс leading/trailing. - Реализуйте поиск с debounce и отменой предыдущего запроса.
- Замените scroll-слушатель на
IntersectionObserver.
Вопросы с ответами
Чем debounce отличается от throttle?
Debounce вызывает функцию после паузы, throttle — не чаще раза за интервал.
Когда что использовать?
Debounce — ввод в поиск, throttle — прокрутка и перетаскивание.