В чем разница между дебаунсом и троттлингом
Что проверяют
Различаете ли вы две техники по поведению во времени, а не по названиям, и умеете ли выбрать нужную под задачу. Следом часто просят написать debounce руками или показать, как не сломать его в React-компоненте.
Как отвечать
Суть укладывается в одно предложение на каждую:
- debounce: вызов откладывается, пока события не прекратятся на заданное время. Каждое новое событие перезапускает таймер, поэтому при непрерывном потоке функция не вызовется, пока пользователь не остановится;
- throttle: функция вызывается не чаще раза в N миллисекунд. При непрерывном потоке вызовы идут равномерно.
Отсюда сценарии. Debounce нужен там, где важен итог: поле поиска с подсказками, автосохранение формы, пересчёт после окончания ресайза. Throttle нужен там, где требуется регулярная реакция во время действия: скролл, mousemove, drag, отправка аналитики о прокрутке.
Хорошо упомянуть режимы leading и trailing. В lodash debounce по умолчанию срабатывает в конце паузы, а throttle и в начале, и в конце интервала. У debounce есть опция maxWait, которая гарантирует вызов хотя бы раз за период и по сути превращает его в троттлинг.
Сильный ответ добавляет альтернативы. Для визуальных обновлений при скролле лучше requestAnimationFrame, он синхронизирован с отрисовкой. Для подгрузки при прокрутке обработчик скролла вообще не нужен: IntersectionObserver сам сообщит, что элемент появился в зоне видимости.
Где спотыкаются
Создают debounced-функцию прямо в теле React-компонента. На каждом рендере получается новая функция со своим таймером, и задержка не работает. Её держат в useRef или useMemo, а при размонтировании вызывают cancel.
Считают, что debounce решает гонку запросов. Он лишь уменьшает их число, а ответ на старый запрос всё равно может прийти позже нового. Устаревший запрос отменяют через AbortController или отбрасывают ответ по идентификатору.
Выбирают throttle для поиска. Тогда запрос уходит на середине слова, а последние буквы теряются, если вызов в конце интервала выключен.