Debounce и throttle в методах

В разработке на Slim.js, как и в других фронтенд-фреймворках, часто возникает необходимость контролировать частоту выполнения методов. Особенно это актуально при обработке событий ввода, прокрутки или изменения размера окна. Для этих целей применяются debounce и throttle — техники оптимизации, позволяющие уменьшить нагрузку на приложение и избежать лишних вызовов функций.


Debounce

Debounce ограничивает вызов метода, гарантируя, что он будет выполнен только после того, как событие прекратилось на заданное время. Это особенно полезно для событий, которые могут происходить очень часто, например input, keyup или resize.

В Slim.js дебаунс можно реализовать через обёртку метода компонента:

class SearchComponent extends Slim {
  constructor() {
    super();
    this.query = '';
    this.debouncedSearch = this.debounce(this.search, 300);
  }

  get template() {
    return `<input type="text" onin put="this.debouncedSearch(event.target.value)" />`;
  }

  search(value) {
    console.log('Search query:', value);
  }

  debounce(func, delay) {
    let timeout;
    return (...args) => {
      clearTimeout(timeout);
      timeout = setTimeout(() => func.apply(this, args), delay);
    };
  }
}

customElements.define('search-component', SearchComponent);

Ключевые моменты:

  • Функция debounce создаёт замыкание, которое хранит идентификатор таймера.
  • clearTimeout предотвращает выполнение предыдущих вызовов.
  • Метод вызывается только один раз после завершения серии событий.

Debounce полезен для:

  • Полей поиска с автоподсказками.
  • Подстройки интерфейса при изменении размеров окна.
  • Обработки событий скролла в интерфейсе, если нужно срабатывать после остановки прокрутки.

Throttle

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

Пример реализации throttle в Slim.js:

class ScrollComponent extends Slim {
  constructor() {
    super();
    this.throttledScroll = this.throttle(this.onScroll, 200);
  }

  get template() {
    return `<div style="height:2000px;" onscr oll="this.throttledScroll(event)"></div>`;
  }

  onScroll(event) {
    console.log('Scroll position:', event.target.scrollTop);
  }

  throttle(func, limit) {
    let lastCall = 0;
    return (...args) => {
      const now = Date.now();
      if (now - lastCall >= limit) {
        lastCall = now;
        func.apply(this, args);
      }
    };
  }
}

customElements.define('scroll-component', ScrollComponent);

Основные моменты:

  • Throttle гарантирует вызов функции не чаще заданного интервала.
  • Полезно для событий прокрутки, ресайза и анимаций, которые должны обновляться с ограниченной частотой.
  • Не блокирует все вызовы, в отличие от debounce — каждый limit интервал гарантированно даёт вызов функции.

Сравнение debounce и throttle

Параметр Debounce Throttle
Когда вызывается После того, как событие прекращается С заданной частотой, пока событие происходит
Применение Поля ввода, автоподсказки, фильтры Скролл, ресайз, анимации, drag-and-drop
Эффект на производительность Уменьшает количество вызовов функций после серии быстрых событий Ограничивает частоту вызовов функции, но позволяет регулярные обновления

Использование с методами Slim.js

Slim.js позволяет привязывать методы к событиям через атрибуты в шаблоне (oninput, onclick, onscroll). Для методов с debounce и throttle рекомендуется:

  1. Создавать обёртку функции в конструкторе или onConnected для сохранения контекста this.
  2. Использовать стрелочные функции при необходимости передачи аргументов.
  3. Не использовать debounce или throttle на методах, которые должны выполняться синхронно и мгновенно для критических действий (например, подтверждение транзакции).

Примеры комбинирования

Иногда требуется комбинировать debounce и throttle. Например, при автосохранении формы с регулярными обновлениями и финальной отправкой после прекращения ввода:

class FormComponent extends Slim {
  constructor() {
    super();
    this.saveThrottle = this.throttle(this.save, 1000);
    this.saveDebounce = this.debounce(this.finalSave, 2000);
  }

  get template() {
    return `<textarea onin put="this.saveThrottle(event); this.saveDebounce(event)"></textarea>`;
  }

  save(event) {
    console.log('Saving draft...', event.target.value);
  }

  finalSave(event) {
    console.log('Final save:', event.target.value);
  }
}

customElements.define('form-component', FormComponent);

Такой подход позволяет обновлять черновик часто, но окончательно сохранять данные только после паузы пользователя.


Debounce и throttle являются мощными инструментами в арсенале Slim.js, позволяя управлять производительностью компонентов, снижать нагрузку на браузер и повышать отзывчивость интерфейса.