Clojurescript ajax.core без отдельного обработчика / обратного вызова, с очень точным потоком в коде, как если бы код был синхронизирован
В JavaScript я мог бы написать такой код, как:
var app_state={"context":"loading"};
$.get("")
.then(function(data){
app_state["data"]=data;
})
.then(change("context", "edit"))
.then(render)
В Clojurescript я бы хотел что-то вроде:
(-> @app-state
(assoc :context "loading")
(assoc :data (GET "")) ;;async call
(assoc :context "edit")
(render))
Не как:
(defn handler [] ...
(GET "" {:handler handler}
2 ответа
Решение
Вот как мы решили это в конце:
(defn fetch-weather [query]
(safe-run
(go
(-> @model
(assoc :text (str "Data for " query))
(assoc :weather
(let [data (<! (GET< (str " http://api" query)))]
{
:temp (- (get-in data ["main" "temp"]) 273.15)
:city query
:country (get-in data ["sys" "country"])
}))
(assoc :context "edit")
(swapm! model))))))
а также
(defn swapm! [x y]
(swap! y (fn [xx] x)))
и безопасный бег - попытка поймать это. Наличие свопа в конце гарантирует, что это будет сделано, только если все остальные операции были в порядке. Так что все или ничего.
Я положил функцию GET внутри функции async-get
который возвращает канал core.async, который в итоге содержит результат операции "GET". Затем я обернуть эти операции в core.async go
блок
; require core.async in ns declaration
;; (:require-macros [cljs.core.async.macros :refer [go]])
;; (:require [cljs.core.async :refer [chan <! >! put! take!]])
(defn async-get
[url]
(let [ch (chan)]
(GET url {:handler (fn [resp]
(put! ch resp))})
ch))
(go
(doto app-state
(swap! assoc :context "loading")
(swap! assoc :data (<! (async-get "")))
(swap! assoc :context "edit")
(render)))