Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Throttle function #267

Open
alphapapa opened this issue Jun 17, 2018 · 2 comments
Open

Throttle function #267

alphapapa opened this issue Jun 17, 2018 · 2 comments
Labels
enhancement Suggestion to improve or extend existing behavior

Comments

@alphapapa
Copy link

I was browsing the CL Serapeum library and came across its throttle function. It seems complementary to dash-functional. I have a function in my Emacs config that I would like to throttle (it plays a notification sound when I get messages in matrix-client; I add it as advice to the built-in notification function), and this works well What do you think?

(defun -throttle (func interval)
  "Throttle FUNC: a closure, lambda, or symbol.

If argument is a symbol then install the throttled function over
the original function.  INTERVAL, a number of seconds or a
duration string as used by `timer-duration', determines how much
time must pass before FUNC will be allowed to run again."
  (cl-typecase func
    (symbol
     (when (get func :throttle-original-function)
       (user-error "%s is already throttled" func))
     (put func :throttle-original-documentation (documentation func))
     (put func 'function-documentation
          (concat (documentation func) " (throttled)"))
     (put func :throttle-original-function (symbol-function func))
     (fset func (throttle--wrap (symbol-function func) interval))
     func)
    (function (throttle--wrap func interval))))

(defun -throttle--wrap (func interval)
  "Return the throttled version of FUNC.
INTERVAL, a number of seconds or a duration string as used by
`timer-duration', determines how much time must pass before FUNC
will be allowed to run again."
  (let ((interval (cl-typecase interval
                    ;; Convert interval to seconds
                    (float interval)
                    (integer interval)
                    (string (timer-duration interval))
                    (t (user-error "Invalid interval: %s" interval))))
        last-run-time)
    (lambda (&rest args)
      (when (or (null last-run-time)
                (>= (float-time (time-subtract (current-time) last-run-time))
                    interval))
        (setq last-run-time (current-time))
        (apply func args)))))

Called like:

(-throttle #'matrix-client-notify-sound "1 second")

It could also be de-throttled with a -throttle-restore function that restores the original definition.

Some of this code is borrowed from Chris Wellons' memoize package.

@magnars
Copy link
Owner

magnars commented Jun 18, 2018

Hi! This looks like a useful function, but it doesn't quite fit the dash-theme. I'd suggest making a separate open source lib with perhaps throttle and debounce in it. :)

@basil-conto
Copy link
Collaborator

basil-conto commented Jun 18, 2018

Maybe I'm just conflating things, but for some reason I had the impression that something like this was already baked into Emacs (though perhaps as part of some specific package, rather than as a general-purpose function). Maybe I'm thinking of progress reporters, or timers, or url.el, I don't know. And all my searches are coming up dry. So feel free to ignore this comment. :)

@Fuco1 Fuco1 added the enhancement Suggestion to improve or extend existing behavior label Jul 26, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Suggestion to improve or extend existing behavior
Projects
None yet
Development

No branches or pull requests

4 participants