我想写一个像时钟应用程序的东西。状态基本上是一个重复递增的数字。在这里可以看到一种做法。
(ns chest-example.core
(:require [om.core :as om :include-macros true]
[om.dom :as dom :include-macros true]
[cljs.core.async :as async])
(:require-macros [cljs.core.async.macros :refer [go]]))
(defonce app-state (atom {:time 0}))
(defn clock-view [data owner]
(reify
om/IRender
(render [_]
(dom/div nil (pr-str data)))))
(go (while true
(async/<! (async/timeout 1000))
(om/transact! (om/root-cursor app-state) :time inc)))
(defn main []
(om/root
clock-view
app-state
{ :target (. js/document (getElementById "clock"))}))
我遇到的问题是这不是可重新加载的代码。一旦我通过无花果轮刷新代码,增量就会变快,因为有几件事情会更新状态。
我试图尝试各种想法(基本上使用不同的组件来拥有go语句代码)但是我无法想出一些可行的东西。
有没有人为此做过一个简洁的解决方案,或者我只是必须在开发过程中坚持使用它?
答案 0 :(得分:2)
你必须告诉goroutine什么时候停止跑步。最简单的方法是发送close!
告诉goroutine:
(ns myproject.core
;; imports
)
(def my-goroutine
(go-loop []
(when (async/<! (async/timeout 1000))
(om/transact! (om/root-cursor app-state) :time inc)
(recur)))))
;; put in your on-reload function for figwheel
(defn on-reload []
(async/close! my-goroutine))
在循环中运行的任何goroutine都需要发出信号以在重新加载时停止(通过figwheel的:on-jsload
配置)。
;; project.clj
(defproject ;; ...
:figwheel {:on-jsload "myproject.core/on-reload"}
)
最好将长时间运行的goroutines视为需要管理的资源。在golang中,将长期运行的goroutine视为流程/墓碑以确保正确拆卸是一种常见模式。同样应该应用于core.async的goroutines。
答案 1 :(得分:0)
确定。在阅读建议后,我自己实施了一些东西。我不能说这是最好的解决方案,所以反馈很受欢迎,但似乎有效。基本上它确实是查尔斯建议的。我将它包装在一个组件中,该组件在添加或删除组件本身时具有回调。我认为无论如何这对于figwheel onload hook来说都很难。
等等!使用,所以我们可以从2个频道获取输入。当组件被移除时#34;从DOM发送:kill信号到alts!退出循环。时钟控制器不会渲染任何内容,只是为了保持时钟滴答并更新应用程序状态,而不是通过任意其他组件通过游标消耗。
(defn clock-controller [state owner]
(reify
om/IInitState
(init-state [_]
{:channel (async/chan)})
om/IWillMount
(will-mount [_]
(go (loop []
(let [c (om/get-state owner :channel)
[v ch] (async/alts! [(async/timeout 1000) c])]
(if (= v :killed)
nil
(do
(om/transact! state :time (fn [x] (+ x 1)))
(recur)))))))
om/IWillUnmount
(will-unmount [_]
(let [c (om/get-state owner :channel)]
(go
(async/>! c :killed)
(async/close! c))))
om/IRender
(render [_])))