Что такое debounce и как он работает в JavaScript?
Что проверяют
Понимаете ли вы механику на таймере и отличаете ли от троттлинга.
Как отвечать
Debounce откладывает вызов функции до тех пор, пока не пройдёт заданная пауза без новых вызовов. Каждый новый вызов сбрасывает таймер. Смысл в том, чтобы выполнить действие один раз, когда поток событий утих.
function debounce(fn, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}Замыкание хранит идентификатор таймера между вызовами, поэтому обёртку надо создать один раз, а не при каждом использовании.
Отличие от троттлинга обязательно назовите: throttle пропускает вызов не чаще одного раза в интервал, то есть срабатывает регулярно во время потока событий. Debounce во время потока не срабатывает вовсе и выполняется один раз после него.
Где что уместно: debounce для поля поиска, автосохранения, валидации при вводе, реакции на изменение размера окна. Throttle для прокрутки, перетаскивания, отправки координат курсора, то есть там, где нужны промежуточные значения.
Что часто требуется дополнительно: отмена (cancel) при размонтировании, немедленный вызов (flush), режим срабатывания по переднему фронту, когда первый вызов проходит сразу, а последующие подавляются.
Отдельно про React: обёртку нельзя создавать в теле компонента без мемоизации, иначе на каждом рендере получится новая функция со своим таймером, и debounce перестанет работать. Нужен useMemo или useRef, плюс отмена в очистке эффекта, чтобы не обновлять состояние размонтированного компонента.
Для запросов к серверу к этому добавляют отмену предыдущего запроса через AbortController: иначе ответы могут прийти не в том порядке, и результат старого запроса перезапишет свежий.
Где спотыкаются
Создают обёртку внутри обработчика или рендера, обнуляя эффект.
Путают debounce и throttle.
Не отменяют таймер при размонтировании.
Забывают отменять устаревшие запросы и получают гонку ответов.