Skip to content

Instantly share code, notes, and snippets.

@vvvvalvalval
Last active August 29, 2015 14:10
Show Gist options
  • Save vvvvalvalval/005eaef8986e20f37d0d to your computer and use it in GitHub Desktop.
Save vvvvalvalval/005eaef8986e20f37d0d to your computer and use it in GitHub Desktop.
Hack for attaching asynchronous callbacks to Clojure promises
(require '[clojure.core.async :as a])
(defn make-promise-listener!
"Creates a function that attaches handlers to Clojure promises.
Behind the scences, fires a loop in another logical thread that scans every refresh-period ms the promises that have been registered for completion,
and executes the each handler on the corresponding value."
[{:keys [refresh-period]
:or {refresh-period 10}}]
(let [next-index! (let [a (atom -1)] #(swap! a inc)) ;; to get unique keys to put in the map.
state (atom {})] ;; map of dummy unique keys to pending promise-handler pairs
(a/go-loop []
(let [period-to (a/timeout refresh-period)]
(doseq [[i {:keys [prom handle!]}] (filter #(-> % second :prom realized?) @state)]
;; for each promise that has been delivered, fires the handler function in another thread
(swap! state dissoc i) ;; when realized, forget about the promise
(a/thread (handle! @prom))) ;; trigger callback in another thread
;; refreshes every refresh-period
(a/<! period-to) (recur)
))
(fn then! [p handle-p!]
(if (and (instance? clojure.lang.IDeref p)
(instance? clojure.lang.IPending p)
(ifn? handle-p!))
(let [i (next-index!), pending {:prom p :handle! handle-p!}]
(swap! state assoc i pending)
nil) ;; return nil so state stays hidden
(throw (RuntimeException. "Wrong params")))
)))
(def then! (make-promise-listener! {})) ;; global promise listener
(comment ;; example
(def my-promise (promise))
(then! my-promise println)
(deliver my-promise "Hello there!") ;; "Hello there!" gets printed
)
;; core.async channel wrapper
(defn as-chan [p]
(let [c (a/chan 1)]
(then! p #(do (a/>!! c %) (a/close! c)))
c))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment