Skip to content

Instantly share code, notes, and snippets.

@scttnlsn
Created March 24, 2014 17:03
Show Gist options
  • Save scttnlsn/9744501 to your computer and use it in GitHub Desktop.
Save scttnlsn/9744501 to your computer and use it in GitHub Desktop.
core.async debounce
(defn debounce [in ms]
(let [out (chan)]
(go-loop [last-val nil]
(let [val (if (nil? last-val) (<! in) last-val)
timer (timeout ms)
[new-val ch] (alts! [in timer])]
(condp = ch
timer (do (>! out val) (recur nil))
in (recur new-val))))
out))
@felixflores
Copy link

Thanks for this 😃

@aiba
Copy link

aiba commented Apr 18, 2016

Nice!

@wilkerlucio
Copy link

nice, just one comment, this implementation has one issue, that is when you close the in channel it gets into an infinite loop by recurring with new-val as nil all the time, the fix is simple, just check the value when receiving from in:

(defn debounce [in ms]
  (let [out (chan)]
    (go-loop [last-val nil]
      (let [val (if (nil? last-val) (<! in) last-val)
            timer (timeout ms)
            [new-val ch] (alts! [in timer])]
        (condp = ch
          timer (do (>! out val) (recur nil))
          in (if new-val (recur new-val)))))
    out))

@danieldroit
Copy link

danieldroit commented Apr 3, 2019

closing the in when out gets closed:

(defn debounce [in ms]
  (let [out (chan)]
    (go-loop [last-val nil]
             (let [val   (if (nil? last-val) (<! in) last-val)
                   timer (timeout ms)
                   [new-val ch] (alts! [in timer])]
               (condp = ch
                 timer (do (when-not
                             (>! out val)
                             (close! in))
                           (recur nil))
                 in (if new-val (recur new-val)))))
    out))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment