Skip to content

Instantly share code, notes, and snippets.

@beders
Last active January 26, 2022 22:18
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save beders/06eeb1d8f49de715c6bd2b84f634cff6 to your computer and use it in GitHub Desktop.
Save beders/06eeb1d8f49de715c6bd2b84f634cff6 to your computer and use it in GitHub Desktop.
Super minimal macro to simplify dealing with promise/async/await code in ClojureScript
(defn create-function-call [param expr]
"Create an sexp for calling expr with a first argument provided by a promise.
If expr is a list (already in form suitable for a function call), insert the first argument at second position,
otherwise turn expr into a function call expression, unless the function is an fn, which is simply returned.
println -> (fn [param] (println param))
(* 2) -> (fn [param] (* param 2))
(fn [result]) -> (fn [result])
"
(if (and (list? expr) (= 'fn (first expr))) ;; expr can be used per se
expr
(list 'fn [param]
(if (list? expr)
(conj (conj (rest expr) param) (first expr))
(list expr param)
)
))
)
(defmacro promise-> [promise & body]
"Chain promises with an optional :catch clause. Works with any promise implementation.
Start with a promise object and then chain as usual.
Returns a promise object.
(promise-> (js/Promise.resolve 1) inc inc js/console.log)
=> #object[Promise [object Promise]]
(prints 3 on console)
Optionally add one ore more :catch error-handler sexp to register a (.catch ...) function:
(promise-> (js/Promise.reject \"error\") inc inc :catch js/console.error)
=> #object[Promise [object Promise]]
(prints \"error\" on console)
"
(let [[body-then [_ & body-catch]] (split-with #(not= :catch %) body)
param (gensym 'result)
]
`(-> ~promise
~@(map (fn [expr] (list '.then (create-function-call param expr))) body-then)
~@(map (fn [expr] (list `.catch (create-function-call param expr))) body-catch)
)))
@beders
Copy link
Author

beders commented Sep 13, 2018

With the latest change, you can also use a fn for the promise callback:

(promise-> (js/Promise.resolve 1) (fn [result] (inc result)))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment