我正在使用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 --
有更好的方法吗?
答案 0 :(得分:1)
我个人会避免使用core.async,除非您的并发足够复杂,以至于承诺还不够。创建和从标准js承诺不需要担心的渠道中提取和提取大量的费用。
为延迟微调器,我将使用防抖功能。也许这会有所帮助:https://www.martinklepsch.org/posts/simple-debouncing-in-clojurescript.html
否则,您可以在Google上执行反跳操作。
基本上,您想这样做:
.finally
,取消所有活动的反跳任务并修改状态以指示您不再加载