3
votes

Context

I'm playing with ClojureScript, so Ajax works as follows for me:

(make-ajax-call url data handler);

where handler looks something like:

(fn [response] .... )

Now, this means when I want to say something like "fetch the new data, and update the left sidebar", my end ends up looking like:

(make-ajax-call "/fetch-new-data" {} update-sidebar!) [1]

Now, I'd prefer to write this as:

(update-sidebar! (make-ajax-call "/fetch-new-data" {})) [2]

but it won't work because make-ajax call returns immediately.

Question

Is there some way via monads, or macros, to make this work? So that [2] gets auto rewritten into [1] ? I believe:

  • there will be no performance penality, since it's rewritten into [1[
  • it's clearer for me to reason about since I can think in synchronous steps rather than async events

    I suspect I'm not the first to run into this problem, so if this is a well known problem, answers of the form "Google for Problem Foo" is perfectly valid.

Thanks!

4
Hi user1383359!, Have my answer (releated with core.async) helped you with this problem? I tried it and works very well - tangrammer
This post is specially related with core.async and doing ajax calls dimagog.github.io/blog/clojure/clojurescript/2013/07/12/… - tangrammer

4 Answers

2
votes

Since Jun 28, 2013, the time that is released clojure core.async lib, you can do it, more or less, in this way: https://gist.github.com/juanantonioruz/7039755

Here the code pasted:

(ns fourclojure.stack
    (require [clojure.core.async :as async :refer :all]))

(defn update-sidebar! [new-data]
  (println "you have updated the sidebar with this data:" new-data))

(defn async-handler [the-channel data-recieved]
  (put! the-channel data-recieved)
  )

(defn make-ajax-call [url data-to-send]
  (let [the-channel (chan)]
    (go   
     (<! (timeout 2000)); wait 2 seconds to response
     (async-handler the-channel (str "return value with this url: " url)))
    the-channel
    )
  )

(update-sidebar! (<!! (make-ajax-call "/fetch-new-data" {})))

More info in:
* http://clojure.com/blog/2013/06/28/clojure-core-async-channels.html
* https://github.com/clojure/core.async/blob/master/examples/walkthrough.clj

1
votes

a macro would change the appearance of the code while leaving the Ajax call asynchronous. it's a simple template macro. another approach would be to wrap the call to make-ajax-call in a function that waits for the result. while either of these could be made to work they may seem a bit awkward and "un ajax like". will the benefits be worth the extra layer of abstraction?

1
votes

What about using the threading macro? Isn't good enough?

(->> update-sidebar! (make-ajax-call "/fetch-new-data" {}))
1
votes

We had rough ideas about this in the async branch of seesaw. See in particular the seesaw.async namespace.