And inconvenient enough to trip up pipeline-async
@ben.sless what do you mean?
In case someone knows how to help 🙂
Possibly not too helpful, but here’s what I wrote when I needed something similar a few weeks ago. Shuts down fine when the input channel closes.
(defn throttle
"Speed limit messages coming into in-ch, echoing to out-chan after a timeout."
[in-ch out-ch]
(go-loop [held-value nil]
(if held-value
(alt!
in-ch ([v] (when v (recur v)))
(a/timeout 500) (do (>! out-ch held-value)
(recur nil)))
(when-let [v (<! in-ch)] (recur v)))))
Yeah, I tried something like that, but it's a throttle indeed, I want somethig that accepts multiple inputs but delay to take a action
anyway, thanks for the input
you are creating a new debounce channel every time you loop in your go loop, you need to create one debounce channel and use the same one for every iteration of your loop
Oh, it makes sense, let me test
Alright, that fixes the issue 😄 but introduce another
If I call multiple times the put!, it does not print the last one only
because the out channel is the same
For example, if I call put! 8 times, it prints 8 times with a delay of 1000ms, I was expecting to print only one time, the last one after the 1000ms
@ericdallo what are the expected semantics? 1. react to first value as soon as possible 2. debounce for timeout (drop all but the last value seen during this time) 3. return the last value (if seen) after timeout 4. repeat (1) ^ Or something else?
the function as written will only consume from the input once a second, and everything it consumes from the input goes to the output
I expect to always debounce, even if the first, second or any time
my description isn't right
• If I call the N time and wait for the ms, it'll print after the ms. • If I call M times inside the ms window, it will print only the last one • every new input, should reset the ms (I expect that from every debounce logic)
Is that clear/makes sense?
if a new input comes in within 1 second of the previous input it should drop the previous
and a new input will cause it to reset the 1 second timer
The way I understand it, debounce does not usually reset ms after every input; debounce usually guarantees the first input is returned as fast as possible and then at most one input is returned after timeout passes (which input is returned is usually specific to the domain)
so with your example code changed so the go-loop is like
(let [c (debounce in 1000)]
(async/go-loop []
(println (async/<! c))
(recur)))
I think it behaves like what you describedif I write a bunch of values all at once, only one is printed, if I write three values with a 500 ms delay between them, only one is printed, if I write three with a 1000 ms delay between them, then all three are printed
Oh, that makes sense! and it's quite simple :man-facepalming: thank you very much @hiredman!
I confirmed it works as I expected
Unless I completely misunderstand the debounce
function, I think I’m doing the same thing: as values come in I recur with the most recent value, discarding earlier values, until a timeout, at which point I flush the last value seen. In fact, the only significant difference seems to be that debounce
does a condp
to determine the channel, whereas I do an alt!
and don’t need that. (Also, the version you posted doesn’t seem protected against input closing; the later one on GitHub looks fine.)
So, perhaps I don’t understand what you’re trying to achieve?
Yes, thanks for the help, I fixed it here: https://clojurians.slack.com/archives/C05423W6H/p1614186680003700 Also I explains exactly what I meant, sorry for not being clear