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)))
Другие вопросы по тегам