← Назад к вопросам

В чем разница между Throttle и Debounce в JavaScript?

1.7 Middle🔥 151 комментариев
#Node.js и JavaScript#Кэширование и производительность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

В чем разница между Throttle и Debounce в JavaScript

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

Debounce откладывает выполнение функции на N миллисекунд после последнего события. Throttle ограничивает частоту выполнения функции — вызывает её максимум один раз за N миллисекунд. Оба используются для оптимизации и экономии ресурсов.

Debounce — ждёшь паузы

// Ждём, пока пользователь закончит печатать
function debounce(func, wait) {
  let timeout;
  return function executedFunction(...args) {
    const later = () => {
      clearTimeout(timeout);
      func(...args);
    };
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
  };
}

// Пример: поиск при вводе
const search = debounce((query) => {
  console.log('Searching for:', query);
  fetch(`/api/search?q=${query}`);
}, 500);

input.addEventListener('input', (e) => {
  search(e.target.value);
});

// Пользователь печатает: а → аб → абв → (ждёт 500ms) → запрос

Когда использовать:

  • Поиск в реальном времени
  • Валидация форм
  • Автосохранение
  • API запросы при изменении

Throttle — вызываешь регулярно

// Вызывай функцию максимум один раз за N миллисекунд
function throttle(func, limit) {
  let inThrottle;
  return function(...args) {
    if (!inThrottle) {
      func.apply(this, args);
      inThrottle = true;
      setTimeout(() => inThrottle = false, limit);
    }
  };
}

// Пример: отслеживание скролла
const handleScroll = throttle(() => {
  console.log('Scroll event');
  updateProgressBar();
}, 1000);

window.addEventListener('scroll', handleScroll);

// За 3 секунды прокрутки будет ~3 вызова вместо 60+

Альтернативная реализация (trailing edge):

function throttle(func, limit) {
  let lastFunc;
  let lastRan;
  return function(...args) {
    if (!lastRan) {
      func.apply(this, args);
      lastRan = Date.now();
    } else {
      clearTimeout(lastFunc);
      lastFunc = setTimeout(() => {
        if (Date.now() - lastRan >= limit) {
          func.apply(this, args);
          lastRan = Date.now();
        }
      }, limit - (Date.now() - lastRan));
    }
  };
}

Когда использовать:

  • Обработка событий скролла
  • Изменение размера окна (resize)
  • Движение мыши
  • Игровые события (обновление позиции)

Наглядное сравнение

Пользователь щёлкает мышкой 5 раз за 1 секунду:

║─────────────────────────────────────────────║
║ События:  │ │ │ │ │ │ │ │ │ │ (10 кликов)  ║
║─────────────────────────────────────────────║

Наивный подход:
✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ (10 вызовов)

Debounce (300ms):
✓           (1 вызов — когда пользователь перестал кликать)

Throttle (300ms):
✓     ✓     ✓     ✓ (4 вызова равномерно)

Практические примеры

1. Поиск с debounce

const searchUsers = async (query) => {
  const response = await fetch(`/api/users?q=${query}`);
  return response.json();
};

const debouncedSearch = debounce(searchUsers, 300);

searchInput.addEventListener('input', (e) => {
  debouncedSearch(e.target.value);
});

2. Скролл с throttle

const updateProgressBar = throttle(() => {
  const progress = (window.scrollY / (document.height - window.innerHeight)) * 100;
  progressBar.style.width = progress + '%';
}, 100);

window.addEventListener('scroll', updateProgressBar);

3. Автосохранение с debounce

const saveFormData = debounce(async (data) => {
  await fetch('/api/save', { method: 'POST', body: JSON.stringify(data) });
  console.log('Saved!');
}, 1000);

form.addEventListener('change', () => {
  saveFormData(new FormData(form));
});

4. Resize обработка с throttle

const handleResize = throttle(() => {
  console.log('Window resized');
  redrawChart();
}, 200);

window.addEventListener('resize', handleResize);

Использование в Node.js (Express, Socket.io)

const express = require('express');
const { throttle } = require('lodash');

const logTraffic = throttle(() => {
  console.log('Traffic check');
}, 5000);

app.use((req, res, next) => {
  logTraffic();
  next();
});

// Socket.io — throttle mouse events с клиента
socket.on('mousemove', throttle((position) => {
  io.emit('cursor', position);
}, 50));

Библиотеки

  • Lodash: _.debounce(), _.throttle()
  • Underscore.js: аналогично
  • Простая реализация: встроить свою (как выше)

Вывод

  • Debounce — для действий, которые должны произойти один раз после паузы
  • Throttle — для действий, которые должны происходить регулярно, но не чаще N раз в секунду
  • Выбор зависит от сценария использования
  • Оба метода критичны для оптимизации производительности
В чем разница между Throttle и Debounce в JavaScript? | PrepBro