Прореживание потока в Kotlin
Быстрые повторы одного сигнала часто означают
промежуточные шаги, а не итог. Функция debounce
ждет паузу между элементами: если за окно
времени приходит новое значение, таймер
сбрасывается, наружу уходит только последнее
после затишья.
Длительность задают типом Duration из
kotlin.time - так проще читать
миллисекунды и секунды:
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.runBlocking
fun main() {
runBlocking {
val bursts = flow {
emit("A")
delay(30)
emit("B")
delay(30)
emit("C")
delay(200)
}.debounce(100.milliseconds)
bursts.collect { token ->
println(token)
}
}
}
После серии коротких emit наружу
попадает одна строка "C" - последняя
перед достаточной паузой. Промежуточные
"A" и "B" отброшены.
Если элементы уже разнесены delay,
debounce пропускает каждый отдельно:
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.runBlocking
fun main() {
runBlocking {
val spaced = flow {
emit(1)
delay(150)
emit(2)
delay(150)
}.debounce(100.milliseconds)
spaced.collect { n ->
println(n)
}
}
}
В консоли и 1, и 2: между
ними тишина длиннее порога. Функция debounce
сочетается с паузами внутри строителя так же,
как с внешними источниками.
Три раза подряд отправьте одну и ту же строку
"tap" с паузой 20
миллисекунд, затем подождите 120
миллисекунд. Примените debounce на
80 миллисекунд и соберите поток -
должна остаться одна строка.
Два числа 10 и 20 отдайте из
потока с 200 миллисекундами между
emit. С debounce в
50 миллисекунд соберите оба
значения по отдельности.