我正在使用 ClojureScript+Rum 构建一个简单的 Web 应用程序,在多个地方我需要使用通过 http/get 请求从服务器获取的数据来显示 UI 片段。
通常我想在数据完全加载之前显示一个微调器。但我不想立即显示它,因为它可能会感觉闪烁(服务器可以足够快地返回响应),所以理想情况下它应该显示一些延迟(比如 300 毫秒)。因此,如果浏览器获得更快的响应,则微调器将不会显示。
如何以理想的 core.async 方式做到这一点?(见下面我的尝试)。
在 http 请求开始时立即开始显示微调器是微不足道的:
(ns my.app
(:require
;; -- snip --
[cljs-http.client :as http]
[cljs.core.async :as ca]))
(defonce *state (atom {:loading false :data nil}))
(defn get-data! []
(go
(swap! *state assoc :loading true)
(let [response (<! (http/get "/api/data"))
data (:body response)]
(swap! *state assoc :loading false :data data))))
;; -- render the data or spinner if :loading --
但是如何延迟显示微调器?我尝试通过将“混合”“超时”和“响应”通道“混合”在一起,然后检查我从结果通道获得的值。它可以工作,但代码感觉很笨拙:
(defonce *state (atom {:loading false :data nil}))
(defn timeout-return [out ms val]
(go
(<! (ca/timeout ms))
(ca/put! out val)))
(defn http-get [out uri]
(go
(let [response (<! (http/get uri))]
(ca/put! out response)
)))
(defn get-data! []
(go
(let [t-out (ca/chan)
resp-out (ca/chan)
out (ca/chan)
mix-out (ca/mix out)
handle-timeout (fn [] (swap! *state assoc :loading true))
handle-resp (fn [r] (swap! *state assoc :loading false :data (:body r)))]
(ca/admix mix-out t-out)
(ca/admix mix-out resp-out)
(timeout-return t-out 400 :timeout)
(http-get resp-out "/api/data")
(let [r (<! out)]
(if (= :timeout r)
(do
(handle-timeout)
(handle-resp (<! out)))
(handle-resp r)))
)))
;; -- render the data or spinner if :loading --
有一个更好的方法吗?