Комментарий пользователя
Здравствуйте! Мой debounce не работает: функция вызывается на каждый input, таймер сбрасывается, но результат все равно моментально выполняется. В чем ошибка?
Ответ специалиста
Здравствуйте, Илья! Чаще всего ошибка — объявление таймера внутри возвращаемой функции (каждый вызов создает свой scope), или потеря контекста this / неправильное использование immediate. Сделайте правильную реализацию, closure для таймера.
function debounce(fn, wait = 200, immediate = false) {
let timeout = null
return function (...args) {
const ctx = this
const later = () => {
timeout = null
if (!immediate) fn.apply(ctx, args)
}
const callNow = immediate && !timeout
clearTimeout(timeout)
timeout = setTimeout(later, wait)
if (callNow) fn.apply(ctx, args)
}
}
Сделайте проверки и убедитесь, что вы присваиваете результат debounce один раз:
const onInput = debounce(handler, 300);
input.addEventListener('input', onInput)
А не:
addEventListener('input', debounce(handler,300))
При каждом рендере.
Если используете React/функциональные компоненты — мемоизируйте debounce с помощью useRef или useCallback, иначе при каждом рендере создается новый закрытый таймаут.
А теперь приступим к тестированию. Быстро печатайте и смотрите, сколько раз вызывается оригинальная функция (лог внутри fn). Затем, проверьте immediate флаг: при immediate=true первая сессия вызовется сразу, последующие будут подавлены до таймаута.
Исправив scope таймера и мемоизацию обработчика, debounce будет работать как ожидается.
Подпишитесь на Академию Selectel и получайте короткие понятные разборы по JavaScript.