В чем разница между Debounce и Throttle (Delay) при обработке событий?

Ответ

Debounce и Throttle (часто путают с простым Delay) — операторы для контроля частоты событий, но с разной логикой.

  • Debounce: Откладывает эмиссию события до тех пор, пока не пройдет заданный интервал (dueTime) без новых событий. "Сбрасывает" таймер при каждом новом входном событии. Идеален для обработки пользовательского ввода (поиск).
  • Throttle: Пропускает первое (или последнее) событие в течение заданного интервала и игнорирует последующие. Не сбрасывает таймер. Полезен для обработки непрерывных действий (скролл, изменение размера).
  • Delay: Простая задержка выполнения на фиксированное время, без логики "сброса" или "пропуска".

Визуализация (поток: A-B-C-D, интервал = 1с):

  • Debounce (latest): Эмитит D (через 1с после него, если новых событий не было).
  • Throttle (first): Эмитит A, игнорирует B и C, затем эмитит D.
  • Throttle (latest): Эмитит A, игнорирует B и C, затем эмитит D.
  • Delay: Эмитит A (через 1с), B (через 1с), и т.д.

Пример Debounce в Combine (Swift):

searchTextField.publisher
    .debounce(for: .milliseconds(500), scheduler: RunLoop.main)
    .sink { query in /* Выполнить поиск */ }

Пример Throttle в Combine (Swift):

scrollViewPublisher
    .throttle(for: .milliseconds(200), scheduler: RunLoop.main, latest: false)
    .sink { /* Обновить UI */ }

Ответ 18+ 🔞

А, вот эта тема, где все путаются, как слепые котята в коробке с болтами! Debounce и Throttle, а ещё туда же какой-то Delay приплетают, будто это одно и то же. Да нет же, ёпта, это три разные, блядь, сущности, у каждой своя хитрая жопа!

Смотри, представь, ты в поисковой строке печатаешь «аниме с большими...» ну, короче, с большими сюжетами. Ты ж не хочешь, чтобы на каждый чих, на каждую букву, серверу летел запрос? Сервер с ума сойдёт, а трафик — овердохуища. Вот тут наш спаситель — Debounce.

Debounce — это такой зануда-перфекционист. Он говорит: «Слушай, чувак, я подожду, пока ты, наконец, угомонишься и перестанешь клацать по клаве. Как только пройдёт N миллисекунд тишины — вот тогда я и сделаю дело». Каждое новое нажатие сбрасывает его внутренний таймер к хуям. Он ждёт паузы. Идеально для поиска, блядь.

А теперь другая история. Ты скроллишь ленту, и на каждый пиксель скролла триггерится какая-нибудь тяжёлая хуйня, типа подгрузки аватарок или расчёта физики. Тут уже Throttle вступает в игру.

Throttle — это рациональный жмот. Он говорит: «Окей, событие есть. Я его пропущу. Но следующие, сука, N миллисекунд — пошли нахуй, я отдыхаю». Таймер не сбрасывается! Он просто открывает форточку раз в N времени и пропускает одно событие (первое или последнее в окне — это уже настройка). Для скролла, ресайза окна — то, что надо.

А Delay? А Delay — это просто тупой, блядь, таймер. Получил событие — подождал фиксированное время — выпустил его. Никакой хитрой логики, никаких сбросов. Полная манда с ушами по сравнению с предыдущими двумя.

Визуализация, чтобы вообще мозг встал на место: Поток событий: A --- B --- C --- D. Интервал 1 секунда.

  • Debounce (latest): Он всех их проигнорит, кроме последнего. Подождёт секунду тишины после D и скажет: «Всё, ладно, эмитим D».
  • Throttle (first): Пропустит A, а потом будет игнорировать B и C, потому что они пришли в течение его окна отдыха. Потом окно откроется, и он пропустит D.
  • Throttle (latest): Почти то же самое, но у него свои приколы с тем, какое событие в окне выбрать.
  • Delay: Ну тут просто. Через секунду после A — эмитит A. Через секунду после B — эмитит B. И так далее. Прямолинейно, как лом.

Код, чтобы не быть просто болтуном:

Вот тебе Debounce для поиска (Combine, Swift):

searchTextField.publisher
    .debounce(for: .milliseconds(500), scheduler: RunLoop.main)
    .sink { query in /* Выполнить поиск, наконец-то! */ }

А вот Throttle, чтобы не ебать UI на каждом скролле:

scrollViewPublisher
    .throttle(for: .milliseconds(200), scheduler: RunLoop.main, latest: false)
    .sink { /* Обновить UI, но без фанатизма */ }

Вот и вся магия. Главное — не путать, а то получится пиздопроебибна в коде, а потом сиди и думай, почему поиск срабатывает на каждую букву, а скролл тормозит, как черепаха в сиропе.