core.async: A Different Approach to Asynchronous Programming with Clojure and ClojureScript
While it has been less than a month since the announcement of the core.async Clojure/ClojureScript library, a number of blog posts have been published describing how to use it effectively to avoid "callback hell" in front-end code, and showing off simple code resulting in some impressive in-browser demos.
core.async offers two ways to write to and read from channels: blocking and non-blocking. A blocking write blocks the thread until the channel has space to be written to (the buffer size of a channel is configurable), a blocking read blocks a thread until a value becomes available on the queue to be read. More interesting, and the only type supported in ClojureScript, are asynchronous channel reads and writes to channels, which are only allowed in "go blocks". Go blocks are written in a synchronous style, and internally converted to a state machine that executes them asynchronously.
Consider the following core.async-based code:
(let [ch (chan)] (go (while true (let [v (<! ch)] (println "Read: " v)))) (go (>! ch "hi") (<! (timeout 5000)) (>! ch "there")))
In this example, let introduces a new local variable ch, which is a new channel. Within the let's scope two go blocks are defined, the first is an eternal loop that reads (<!) a new value from channel ch into variable v. It then prints "Read: " followed by the read value to the standard out. The second go block writes (>!) two values to channel ch: "hi", it then waits 5 seconds and then writes "there" to the channel. Waiting for 5 seconds is implemented by reading from a timeout channel, which is a channel that closes itself (returns nil) after a set timeout. When running this code in the Clojure REPL (for instance), it will return instantly. It will then print "Read: hi", and 5 seconds later it will print "Read: there".
Here are some resources to learn more about core.async and how it can impact front-end web development:
- core.async announcement
- Communicating sequential processes (with in-line interactive demos)
- core.async walkthrough
- Escaping callback hell with core async
- Clojure core.async and Go: a code comparison
- Think Relevance podcast interview with Rich Hickey about core.async