https://kotlinlang.org logo
#reaktive
Title
# reaktive
o

Omar Mainegra

04/30/2020, 4:31 PM
Hi everyone, I'm investigating an issue with
debounce
in iOS, for some reason is NOT waiting the
timeout
Copy code
@Test
fun `'debounce' using Main scheduler works`() {
    val timeout = 10L
    val time = getTimeMillis()
    val wasCalled = AtomicBoolean(false)

    observableOf(1, 2, 3, 4, 5)
        .debounce(timeout, mainScheduler)
        .subscribe { value ->
            val elapsed = getTimeMillis() - time
            assertTrue("Should have passed more than $timeout millis, but was $elapsed") { elapsed >= timeout }
            assertEquals(5, value)

            wasCalled.value = true
        }

    await(2*timeout.toInt())
    assertTrue("`subscribe` was not called") { wasCalled.value }
}
The test fails
kotlin.AssertionError: Should have passed more than 10 millis, but was 1
But it works with
ioScheduler
and
computationScheduler
,
also if
delay
is used instead of
debounce
it works as well. PS: The
await
functions just runs the current Loop:
Copy code
private fun await(millis: Int) {
    NSRunLoop.currentRunLoop.runUntilDate(NSDate.dateWithTimeInterval(millis.toDouble()/1000.0, NSDate.now))
}
a

Arkadii Ivanov

04/30/2020, 4:44 PM
Hello, if I'm not missing something the subscribe block should be called with a single value
5
almost immediately after subsription. The output looks correct.
This is your case:
o

Omar Mainegra

04/30/2020, 4:46 PM
Hi, thanks for the response, according to the doc (and the bubble diagram) there's an initial delay
a

Arkadii Ivanov

04/30/2020, 4:46 PM
Where do you see an initial delay?
o

Omar Mainegra

04/30/2020, 4:47 PM
a

Arkadii Ivanov

04/30/2020, 4:47 PM
You mean the delay between first blue "1" and its emission?
o

Omar Mainegra

04/30/2020, 4:47 PM
The first element is emitted after the
timeout
as well
Yes
a

Arkadii Ivanov

04/30/2020, 4:48 PM
But in your case the second element is emitted straightaway which "overrides" the first one
o

Omar Mainegra

04/30/2020, 4:49 PM
Yes, the seconds elements "resets" the timer, but it should be emitted after the timeout elapsed (This is what I expect)
a

Arkadii Ivanov

04/30/2020, 4:50 PM
No, as soon as items are emitted by upstream and the time between emissions is less than timeout, nothing will be emitted
Basically every emission from upstream resets the timer. Emission to downstream is performed when the timer reaches timeout.
Or when upstream completes
o

Omar Mainegra

04/30/2020, 4:52 PM
Exactly, and in my case is not when it reaches the timeout, but immediately
a

Arkadii Ivanov

04/30/2020, 4:52 PM
I don't understand
o

Omar Mainegra

04/30/2020, 4:53 PM
In any case, whatever element is emitted, it should be after the timeout (at least)
a

Arkadii Ivanov

04/30/2020, 4:53 PM
No, because upstream complets
This forces debounce to emit
o

Omar Mainegra

04/30/2020, 4:53 PM
AHhh I see
Good point, let me rewrite the test case
a

Arkadii Ivanov

04/30/2020, 4:54 PM
Yep, something like:
Copy code
observable<Int> { (1..5).forEach(it::onNext) }
👀 1
Without completion it should emit the last value after timeout
o

Omar Mainegra

04/30/2020, 4:56 PM
👏 Indeed
Thanks
👍 1
a

Arkadii Ivanov

04/30/2020, 5:00 PM
You are welcome
6 Views