Throttling и debouncing

В работе с событиями DOM часто возникает необходимость контролировать частоту вызова функций, особенно при интенсивных событиях, таких как scroll, resize или mousemove. Библиотека ally.js предоставляет удобные инструменты для управления доступностью и взаимодействием, но для оптимизации производительности и предотвращения перегрузки браузера важно комбинировать её с подходами throttling и debouncing.


Debouncing

Debouncing — это метод, при котором функция вызывается только после того, как событие перестало происходить в течение определённого времени. Он эффективен для предотвращения лишних вызовов при непрерывных событиях.

Принцип работы

  1. Пользователь совершает серию событий (например, быстро скроллит страницу).
  2. Каждое событие сбрасывает таймер.
  3. Функция выполняется только один раз после того, как события прекратились и таймер истёк.

Пример использования с ally.js

import { focusWithin } fr om 'ally.js';

function highlightFocusedElement() {
  const element = focusWithin();
  if (element) {
    element.classList.add('highlight');
  }
}

// Debounce функция с задержкой 300 мс
function debounce(func, wait) {
  let timeout;
  return function(...args) {
    clearTimeout(timeout);
    timeout = setTimeout(() => func.apply(this, args), wait);
  };
}

const debouncedHighlight = debounce(highlightFocusedElement, 300);

document.addEventListener('focusin', debouncedHighlight);

В этом примере функция highlightFocusedElement вызывается только после того, как пользователь перестал переключать фокус на элементы на 300 мс. Это снижает нагрузку на DOM и предотвращает частые изменения классов.


Throttling

Throttling ограничивает частоту вызова функции, позволяя выполнять её не чаще, чем один раз за заданный интервал времени. Этот подход полезен для событий, происходящих с высокой скоростью, где важно получать обновления с определённой периодичностью.

Принцип работы

  1. Пользователь вызывает событие многократно.
  2. Функция выполняется не чаще одного раза за указанный период.
  3. Остальные вызовы игнорируются до окончания периода.

Пример использования с ally.js

import { tabFocus } fr om 'ally.js';

function logTabFocus() {
  const focusedElement = tabFocus();
  if (focusedElement) {
    console.log('Focused element:', focusedElement);
  }
}

// Throttle функция с интервалом 200 мс
function throttle(func, lim it) {
  let lastCall = 0;
  return function(...args) {
    const now = Date.now();
    if (now - lastCall >= lim it) {
      lastCall = now;
      func.apply(this, args);
    }
  };
}

const throttledLogFocus = throttle(logTabFocus, 200);

document.addEventListener('keydown', throttledLogFocus);

Здесь logTabFocus будет выполняться не чаще одного раза каждые 200 мс, даже если пользователь быстро переключает фокус с помощью клавиши Tab.


Сравнение Debounce и Throttle

Характеристика Debounce Throttle
Когда вызывается функция После окончания серии событий С периодичностью во время событий
Применение Ввод текста, поиск, изменения размера окна Скролл, движение мыши, анимации
Эффект Минимизирует вызовы до одного Контролирует частоту вызовов

Практическая интеграция с ally.js

Debounce идеально подходит для функций, которые реагируют на события focus или ввод текста, например:

  • Проверка видимости элементов для доступности с focusWithin.
  • Валидация полей формы при вводе пользователя.

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

  • Отслеживание позиции клавиатурного фокуса с tabFocus.
  • Активация подсветки доступных интерактивных элементов при скролле страницы.

Создание универсального инструмента для ally.js

Можно объединить debounce и throttle в одну обёртку для управления событиями, где выбор метода зависит от характера события:

function createEventHandler(func, { mode = 'debounce', delay = 200 }) {
  if (mode === 'debounce') {
    return debounce(func, delay);
  } else if (mode === 'throttle') {
    return throttle(func, delay);
  }
  return func;
}

const handleFocusChange = createEventHandler(highlightFocusedElement, { mode: 'debounce', delay: 300 });
const handleScrollFocus = createEventHandler(logTabFocus, { mode: 'throttle', delay: 150 });

document.addEventListener('focusin', handleFocusChange);
document.addEventListener('scroll', handleScrollFocus);

Такой подход позволяет оптимизировать производительность и сохранять реактивность интерфейса, используя возможности ally.js для управления доступностью.