I did a bit of frontend work for internal tools recently and chose to go with clojurescript, for obvious reasons.
Like clojure, clojurescript supports macros which let you express common lengthy idioms. I use the jayq library to interact with the browser since JQuery is the de-facto standard and battle tested.
A standard call to a JSON get in JQuery looks like this:
$.getJSON('ajax/test.json', function(data) { doSomethingWith(data); });
Which is really a call to:
$.ajax({
url: 'ajax/test.json',
dataType: 'json',
success: function(data) { doSomethingWith(data); }
});
Now when using `jayq` this would translate to:
(ajax "ajax/test.json" {:dataType "json" :success (fn [data] (do-something-with data))})
This is just as simple, but a bit lacking in terms of readability, with a simple, add to this that you might want to check the `done` status of the resulting future and you end up with:
(let [ftr (ajax "ajax/test.json" {:dataType "json" :success (fn [data] (do-something-with data))})] (.done ftr (fn [] (refresh-view))))
Thankfully, with macros we can make this much prettier, with these two simple macros:
(defmacro when-done [ftr & body] `(.done ~ftr (fn [] ~@body))) (defmacro with-json [sym url & body] `(jayq.core/ajax ~url {:dataType "json" :success (fn [data#] (let [~sym (cljs.core/js->clj data#)] ~@body))}))
We can now write:
(when-done (with-json data "ajax/test.json" (do-something-with data))
(refresh-view))
Which clearly turns down the suck on the overall aspect of your callback code.
There's a lot more to consider of course, as evidenced by this PR, but it's a good showcase of clojurescript's abilities.