0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-24 07:29:08 -05:00

🐛 Fix unexpected rx scheduler saturation on mouse movement burst

Fixed with custom trailing-edge throttling mechanism
This commit is contained in:
Andrey Antukh 2023-12-14 17:25:49 +01:00 committed by Alonso Torres
parent ccf063b8ef
commit 88c7ac379b
2 changed files with 74 additions and 1 deletions

View file

@ -19,6 +19,7 @@
[app.util.globals :refer [global]]
[app.util.mouse :as mse]
[app.util.object :as obj]
[app.util.rxops :as rxs]
[app.util.time :as dt]
[beicon.v2.core :as rx]
[clojure.set :as set]
@ -82,7 +83,7 @@
;; position changes.
(->> stream
(rx/filter mse/pointer-event?)
(rx/sample 50)
(rx/pipe (rxs/throttle 100))
(rx/map #(handle-pointer-send file-id (:pt %)))))
(rx/take-until stoper))]

View file

@ -0,0 +1,72 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.util.rxops
(:require
[beicon.v2.core :as rx]))
(defn- throttle-fn
[delay f]
(let [state
#js {:lastExecTime 0
:timeoutId nil
:context nil
:args nil}
execute-fn
(fn []
(let [context (.-context ^js state)
args (.-args ^js state)]
(.apply f context args)
(set! (.-lastExecTime state) (js/Date.now))
(set! (.-timeoutId state) nil)))
wrapped-fn
(fn []
(let [ctime (js/Date.now)
ltime (.-lastExecTime ^js state)
args (js-arguments)]
(this-as this
(set! (.-context state) this)
(set! (.-args state) args))
(let [timeout-id (.-timeoutId state)]
(if (>= (- ctime ltime) delay)
(do
(when ^boolean timeout-id
(js/clearTimeout timeout-id)
(set! (.-timeoutId state) nil))
(execute-fn))
(when-not ^boolean timeout-id
(set! (.-timeoutId state)
(js/setTimeout execute-fn (- delay ctime ltime))))))))]
(specify! wrapped-fn
rx/IDisposable
(-dispose [_]
(js/clearTimeout (.-timeoutId state))
(set! (.-lastExecTime state) 0)
(set! (.-timeoutId state) nil)))))
(defn throttle
"High performance rxjs throttle operation. It does not saturates the
macro-task queue of the js runtime on long burst of mouse
movements."
[delay]
(fn [source]
(rx/create
(fn [subs]
(let [next-fn (throttle-fn delay (partial rx/push! subs))
error-fn (fn [cause]
(rx/dispose! next-fn)
(rx/error! subs cause))
end-fn (fn []
(rx/dispose! next-fn)
(rx/end! subs))]
(rx/sub! source next-fn error-fn end-fn))))))