4

我想写一个时钟应用程序之类的东西。状态基本上是一个重复递增的数字。一种方法可以在这里看到。

(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 语句代码),但我无法想出可行的方法。

有没有人对此有一个很好的解决方案,还是我只需要在开发过程中坚持下去?

4

2 回答 2

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"}
)

最好将长时间运行的 goroutine 视为需要管理的资源。在 golang 中,将长时间运行的 goroutines 视为进程/墓碑以确保正确拆卸是一种常见的模式。core.async 的 goroutine 也应如此。

于 2015-05-16T10:05:43.870 回答
0

好的。在阅读了建议后,我尝试自己实施一些东西。我不能声称这是最好的解决方案,因此欢迎提供反馈,但它似乎有效。基本上它符合查尔斯的建议。我将它包装在一个组件中,该组件具有添加或删除组件本身时的回调。我认为无论如何这都很难用figwheel onload hook来做。

小号!使用,因此我们可以从 2 个通道中获取输入。当组件从 DOM 中“移除”时,它会向 alts 发送 :killed 信号!退出循环。

时钟控制器不会渲染它存在的任何东西,基本上只是为了保持时钟滴答作响并更新应用程序状态,而不是通过游标被任意其他组件消耗。

(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 [_])))
于 2015-05-21T02:55:14.030 回答