DEV Community

Discussion on: Throttle/debounce a Common Lisp function

Collapse
 
vindarel profile image
vindarel

Here's another version: gitlab.com/fstamour/cache-cache/-/...

(defun make-debouncer (delay-in-seconds callback)
  ;; TODO there's probably a bunch of race conditions...
  (let ((last-time)
        (thread)
        (saved-args))
    (labels ((now ()
               (/ (get-internal-real-time)
                  #.(float internal-time-units-per-second)))
             (update-last-time (now)
               (setf last-time now))
             (overduep (now)
               (and last-time
                    (<= delay-in-seconds (- now last-time))))
             (actually-call (now args)
               (update-last-time now)
               (setf thread nil)
               (apply callback args))
             (wait-loop ()
               (loop
                 :for now = (now)
                 :until (overduep now)
                 :do (let ((delay (max 0.025 (- (+ last-time delay-in-seconds) now))))
                       #++ (progn (format *debug-io* "~&About to sleep ~s seconds" delay)
                                  (force-output *debug-io*))
                       (sleep delay)))
               (actually-call (now) saved-args))
             (maybe-funcall (&rest args)
               (update-last-time (now))
               (setf saved-args args)
               (unless thread
                 (setf thread (bt:make-thread #'wait-loop
                                              :name "Debouncer thread")))
               last-time))
      #'maybe-funcall)))
Enter fullscreen mode Exit fullscreen mode

no macro \o/

A single thread waits a minimum amount of time, in the meantime the arguments given from the user are updated.

reminder: labels is like let but to create local functions.