Что такое debounce?

MiddleJavaScript #javascript #performance

Вопрос

Что такое debounce и когда его применяют?

Короткий ответ

Debounce — это техника, которая откладывает вызов функции до тех пор, пока не пройдёт заданная пауза без новых вызовов: каждый новый вызов сбрасывает таймер заново, и функция реально выполняется только один раз — после того как события перестали приходить.

Подробный ответ

Debounce используют, чтобы не выполнять дорогую операцию (запрос к серверу, сложный рендер, валидацию) на каждое срабатывание частого события — ввод текста, resize окна, скролл. Вместо этого функция выполняется один раз, когда пользователь "успокоился".

Реализуется через setTimeout и замыкание, которое хранит идентификатор таймера между вызовами:

  1. При каждом вызове debounced-функции предыдущий таймер отменяется (clearTimeout).
  2. Ставится новый таймер на delay мс.
  3. Если за это время новых вызовов не было — оригинальная функция выполняется.

Debounce стоит отличать от throttle: throttle гарантирует, что функция выполняется не чаще, чем раз в delay мс (равномерно, независимо от того, прекратился поток событий или нет), а debounce откладывает выполнение до полной паузы.

Пример

function debounce(fn, delay) {
  let timeoutId
  return function (...args) {
    clearTimeout(timeoutId)
    timeoutId = setTimeout(() => fn.apply(this, args), delay)
  }
}

const input = document.querySelector('#search')
const handleSearch = debounce((event) => {
  fetch(`/api/search?q=${event.target.value}`)
}, 300)

input.addEventListener('input', handleSearch)
// Запрос уйдёт на сервер только через 300мс после того,
// как пользователь перестал печатать

Дополнительные вопросы

  • Чем debounce отличается от throttle и когда что использовать?
  • Как реализовать debounce с "немедленным" первым вызовом (leading edge)?
  • Как debounce/throttle реализованы в популярных библиотеках (lodash, VueUse)?