conquerant icon indicating copy to clipboard operation
conquerant copied to clipboard

lightweight async/await for Clojure

conquerant

async/await for Clojure

Clojars Project Build Status codecov

A lightweight Clojure wrapper around ForkJoinPool and CompletableFuture for concurrency that is simple and easy.

Why

core.async

Usage

;; Async HTTP Exaxmple
;; ===================
(refer-clojure :exclude '[await promise])
(require '[clj-http.client :as client]
         '[conquerant.core :refer [async await promise]])

(def url "https://gist.githubusercontent.com/divs1210/2ce84f3707b785a76d225d23f18c4904/raw/2dedab13201a8a8a2c91c3800040c84b70fef2e2/data.edn")

(defn fetch [url]
  (promise [resolve]
    (client/get url
                {:async? true}
                (fn [response]
                  (resolve [response nil]))
                (fn [error]
                  (resolve [nil error])))))

(async
  (let [[response error] (await (fetch url))]
    (if error
      (println "Error:" (.getMessage error))
      (println "Response Body:" (:body response)))))

(println "fetching asynchronously...")
;; => fetching asynchronously...
;; => Response Body: {:result 1}
  • promise

    • gets value out of callback
    • runs body on a lightweight thread, returning a CompletableFuture
    • can be resolved from outside via complete
    • can be derefed: @(promise [resolve] (resolve :hi))
    • can run on a custom ExecutorService using with-async-executor
  • async

    • runs body on a lightweight thread
      • can wrap defn and fn forms - supports variadic versions
      (async (defn f
               ([a]
                 (inc a))
               ([a b]
                 (* a b))))
      
      • any other expression, returning a CompletableFuture (promise)
      @(async [1 2]) ;; => [1 2]
      
    • can run on a custom ExecutorService using with-async-executor
  • await

    • pauses the lightweight thread till the given promise is complete
    • can only be used in async let bindings
      • normal let block anywhere inside an async block
      • every let block with a call to await returns a CompletableFuture
    • works across function boundaries
    • can timeout like deref: (await p 1000 :timeout)
  • channels

    • supports core.async-like channel operations! (experimental!)

Walkthrough

Clone this repo, fire up a REPL, and walk through the conquerant walkthrough.

License

Copyright © 2018 Divyansh Prakash

Distributed under the Eclipse Public License either version 1.0.