(ns example.asyncq
(:require
[cljs.core.async :as async]
goog.async.AnimationDelay)
(:require-macros
[cljs.core.async.macros :refer [go go-loop]]))
(defn loop-fx-on-atm-when-pred?-is-true [atm fx pred?]
(let [c (async/chan)
f (goog.async.AnimationDelay. #(async/put! c :loop))
a (atom false)]
(add-watch
atm
:loop-fx-on-atm-when-pred?-is-true
(fn [_ _ _ _]
(when-not @a
(async/put! c :initial-loop))))
(go-loop []
(async/<! c)
(reset! a true)
(swap! atm #(if (pred? %) (do (.start f) (fx %)) %))
(reset! a false)
(recur))))
(def the-final-countdown (atom 4))
(loop-fx-on-atm-when-pred?-is-true
the-final-countdown
#(do (js/console.log %) (dec %))
pos?)
(swap! the-final-countdown inc)
;; prints "5" "4" "3" "2" "1", each on a seperate frame (hearbeat)
The purpose of loop-fx-on....
is to register fx
to be called on atm
(per heartbeat) whenever pred? @atm
pred? @atm
is true
.
I would like the following properties:
pred?
might return true
. Otherwise, the state machine sits idle. f
to be called again. pred?
returns false. My biggest gripe with the above code is (reset! a true)
and (reset! a false)
around the swap!
. That is really ugly, and in a non single threaded environment would probably be a bug. Is there any way to improve this code so that I don't end up using a
?
My second concern is that 2 is not being met. Currently, if you modify the same atom twice between a frame, it will actually result in 2 calls to (f); or 2 callbacks on the next frame. I could use another atom to record whether I have actually registered for this frame or not, but this is already getting messy. Anything better?
Something like this might work for you:
(defn my-fn [a f pred]
(let [pending? (atom false)
f (fn []
(reset! pending? false)
(f @a))]
(add-watch a (gensym)
(fn [_k _a _old-val new-val]
(when (and (not @pending?) (pred new-val))
(reset! pending? true)
(if (exists? js/requestAnimationFrame)
(js/requestAnimationFrame f)
(js/setTimeout f 16)))))))
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.