Skip to content

Instantly share code, notes, and snippets.

@jaidetree
Last active April 4, 2020 16:05
Show Gist options
  • Save jaidetree/1d84d332a8afc9dcc1dbb48309811407 to your computer and use it in GitHub Desktop.
Save jaidetree/1d84d332a8afc9dcc1dbb48309811407 to your computer and use it in GitHub Desktop.
A WIP library of promise macros for ClojureScript
(ns cljs.promise
(:refer-clojure :exclude [resolve]))
(defmacro promise
"
Example:
(promise (resolve 5))
(promise (reject (js/Error. \"oops\")))
"
[body]
`(js/Promise. (fn [~'resolve ~'reject] ~body)))
(defmacro promise->
"
Example:
(promise-> (.resolve js/Promise {}) $
(assoc $ :a 1)
(assoc $ :b 2)
(println))
;; => {:a 1 :b 2}
;; => #object[Promise [object Promise]]
"
[expr name & forms]
`(let [~name ~expr]
(-> ~name
~@(map (fn [form]
`(.then (fn [~name]
~form))) forms))))
(defmacro then
"
Example:
(-> (promise (resolve {}))
(then [resources] (-> (.launch \"puppeteer\")
(then [browser]
(assoc resources :browser browser)))))
"
([a-promise body]
`(.then
~a-promise
(fn ~'success
[]
~body)))
([a-promise bindings & body]
`(.then
~a-promise
(fn ~'success
~bindings
~@body))))
(defmacro catch
"
Example:
(-> (promise (reject \"err\"))
(catch [msg] (println msg)))
"
([a-promise body]
`(.catch ~a-promise
(fn catch
[]
~body)))
([a-promise bindings body]
`(.catch ~a-promise
(fn catch
~bindings
~body))))
(defmacro resolve
"
Example:
(resolve {})
"
[x]
`(.resolve js/Promise ~x))
(defmacro reject
"
Example:
(reject {})
"
[x]
`(.reject js/Promise ~x))
(ns cljs.async
(:refer-clojure :exclude [delay])
(:require-macros
[cljs.promise :refer [promise->] :as p]))
(defn resources
"
Example:
(resources
:browser (fn []
(.launch puppeteer))
:page (fn [{:keys [browser]}]
(promise-> (.pages browser) pages
(nth pages 0)))
nil (fn [{:keys [page]}]
(.goto page \"https://google.com\")))
"
[init & resources]
(reduce
(fn [res [name setup]]
(println name res)
(if name
(promise-> res resources
(promise-> (setup resources) resource
(assoc resources name resource)))
(promise-> res resources
(setup resources)
res)))
(p/resolve init)
(partition 2 resources)))
(defn tasks
"
Example:
(tasks {}
(fn [{:keys [page]}]
(.click page \"play\")))
"
[res & tasks]
(let [res-promise (p/resolve res)]
(reduce
(fn [chain task]
(promise-> res-promise res-map
(task res-map)
res-promise))
tasks)))
(defn timeout
"
Example:
(-> (timeout (* 7 60 1000))
(p/then (println \"pizza is ready\") ))
"
[ms]
(p/promise
(js/setTimeout #(resolve (.now js/Date)) ms)))
(defn delay
"
Example:
(-> (delay (* 7 60 1000) \"pizza is ready\")
(p/then [msg] (println msg) ))
"
[ms x]
(-> (timeout ms)
(p/then [_] x)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment