Clojurescript ajax.core 没有单独的 handler/callback,代码中的流程非常精确,就好像代码是同步的

Clojurescript ajax.core without separate handler/callback, with very precise flow in the code as if the code was sync

在 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}

我将 GET 函数放在函数 async-get 中,其中 returns 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)))

最后我们是这样解决的:

(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)))

和 safe-运行 是一个绕过它的尝试。最后进行交换可确保仅在所有其他操作都正常时才完成交换。所以这是全有或全无。