27

Everybody is talking about how great core.async is, and how it will improve event handling in clojurescript. I've been following the ClojureScript 101 tutorial, and I don't see any clear advantage from these code examples. What am I missing?

Why is the use of core.async any better here?

(defn listen [el type]
  (let [out (chan)]
    (events/listen el type
      (fn [e] (put! out e)))
    out))

(defn dosomethingasync
  [e]
  (js/console.log "async: " e))

(let [clicks (listen (dom/getElement "search1") "click")]
  (go (while true (dosomethingasync (<! clicks)))))

vs.

(defn dosomethingcallback
   [e]
   (js/console.log "callback: " e))

(events/listen (dom/getElement "search2") "click" dosomethingcallback)
Imogen
  • 361
  • 3
  • 6

1 Answers1

35

Great question!

I think your first step to understand the advantage would be Timothy Baldridge Video

And below my try:

I think that the differences will clear up if we change a bit your code.

Firstly, trying to highlight the sentence "There comes a time in all good programs when components or subsystems must stop communicating directly with one another" extracted from the presentation of core.async posted on the clojure blog. I think that we can separate the input events channel from the let fn:

(def clicks (listen (dom/getElement "search1") "click"))

(go
  (while true
    (dosomethingasync (<! clicks))))

(put! clicks "this channel can be written from differents parts of your code")

Secondly, with core.async we can write asynchronous calls as we'll write synchronous calls (sequential code). An example of this situation require more than one channel:

(def clicks (listen (dom/getElement "search1") "click"))

(def keys-pressed (listen (dom/getElement "search1") "keypress"))

(def to-out (chan))

(go
  (while true
    (let [click-recieved (<! clicks)]
      (dosomethingasync click-recieved)
      (>! to-out "click recieved!")
      (let [other-input-waited (<! keys-pressed)]
        (dosomethingwithkey other-input-waited)
        (>! to-out "keypressed recieved!")
        )
      )
    ))

And lastly, i think that you are not properly using the meaning of callback function. When we talk of a callback function i think we are referring to a function that besides its own parameters it receives a function "callback". At the end of the execution of the function we call the callback function to return the execution flow to the original point. Changing your "callback" function come up as follow:

(defn dosomethingcallback
   [e call-back-fn]
   (js/console.log "callback: " e)
   (call-back-fn))

And if we try to issue something similar to the same behaviour achieved with previous code core.async example:

(defn do-key
   [call-back-fn e]
   (.log js/console "before  callback key" )
   (call-back-fn e))

(defn do-click
   [call-back-fn e]
   (.log js/console "before callback click")
   (call-back-fn e))

(defn key-callback-fn [e]
  (.log js/console (str "doing some work with this key: " e))
  )

(defn click-callback-fn [e]
  (.log js/console (str "doing some work with this click" e))
  (events/listen (dom/getElement "search2") "keypress" (partial do-key key-callback-fn)))


  (events/listen (dom/getElement "search2") "click" (partial do-click click-callback-fn))
tangrammer
  • 3,011
  • 15
  • 23