When I start developing in ClojureScript one year ago, core.async was ( and surelly continues to be) the most adopted library for work with asynchronous code.
It is not very bad approach because core.async is a great library, but in my opion is not a good abstraction for represent a result of async computation because it does not has builtin mechanism for handling errors.
Due to no existence of well established, documented and high performance promise library for clojurescript until today, I have written promesa.
It uses the the powerful and high performant bluebird promise library as underlying implementation for ClojureScript and jdk8 completable futures as underlying impl. for Clojure.
This is a quick preview of the api
(require '[promesa.core :as p]) (->> (p/all [(do-some-async-job) (do-some-other-async-job)]) (p/map (fn [[result1 result2]] (do-stuff result1 result2))) (p/err (fn [error] (do-something-with-error error))))
Other of the amazing things that promesa library exposes, is the ability to compose async computations that looks synchronous:
(defn do-stuff  (p/alet [x (p/await (p/promise 1)) ;; do async operation _ (p/await (p/delay 1000)) ;; emulate sleep y (p/await (p/promise 2))] ;; do an other async operation (+ x y))) ;; do the operation with results ;; of previous two async operations (p/map #(println %) (do-stuff))
The result of
alet expression is an other promise that will be resolved with result
of final operation or rejected in case of one of its operations is rejected.
This post only shows a little portion of the available api. If you want know more, the promesa documentation has a lot of examples.