Ответ
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, но без фанатизма */ }
Вот и вся магия. Главное — не путать, а то получится пиздопроебибна в коде, а потом сиди и думай, почему поиск срабатывает на каждую букву, а скролл тормозит, как черепаха в сиропе.