Clojurescript + Om:等待状态改变,然后做点什么

时间:2014-06-29 19:44:25

标签: clojure clojurescript core.async om secretary

我正在尝试制作一个显示食谱的Clojurescript应用程序。

相关代码如下(也可用as a gist):

(defn load-recipes [data]
  (go (if (not (:loaded? @data))
        (let [recipes-data (<! (fetch-recipes data))]
          (om/update! data :recipes recipes-data)
          (om/update! data :loaded? true))
        (println "Data already loaded"))))

(defn define-routes [data]
  (defroute home-path "/" []
    (om/update! data :view :home))
  (defroute "/random" []
    (go (loop [loaded? (:loaded? (om/value data))]
          (if-not loaded? (do (println "Waiting for data...")
                              (recur (:loaded? (om/value data))))
                  (do (om/update! data :tag
                                  (rand-nth
                                   (vec (apply set/union (map :tags (:recipes @data))))))
                      (om/update! data :view :random)))))))

(defn app-view [data owner]
  (reify
    om/IWillMount
    (will-mount [_]
      (do
        (load-recipes data)
        (define-routes data)))
    om/IDidMount
    (did-mount [_]
      #_(fetch-recipes data))
    om/IRender
    (render [_]
      (html data))))

我想要完成的事情:

  • 首先使用异步http调用获取配方。我正在使用返回频道的cljs-http.client
  • 使用秘书库定义路线。在/ random路线中,我想选择一个随机配方。这只能在获取数据并在应用程序原子中更新时才会发生。

我现在得到的是浏览器中的无限循环。发生了什么事?

另一种选择是在go块中包装首先需要数据获取的所有路由,并将(<! (load-recipes))放在第一行。

PS:我最终得到了

(defn ensure-recipes-loaded [data]
  (go (if (not (:loaded? (om/value data)))
        (do (om/update! data :view :loading)
            (let [recipes-data (<! (fetch-recipes data))]
              (om/update! data :recipes recipes-data)
              (om/update! data :loaded? true)))
        (println "Data already loaded"))))

(defn define-routes [data]
  (defroute home-path "/" []
    (om/update! data :view :home))
  (defroute "/random" []
    (go
      (<! (ensure-recipes-loaded data))
      (do (om/update! data :tag
                      (rand-nth
                       (vec (apply set/union (map :tags (:recipes @data))))))
          (om/update! data :view :random))))
  (defroute "/random/:tagname" [tagname]
    (go (<! (ensure-recipes-loaded data))
        (om/update! data :tag tagname)
        (om/update! data :view :random)))

  (defroute "/recipe/:link" [link]
    (go (<! (ensure-recipes-loaded data))
        (om/update! data :view :recipe)
        (om/update! data :permalink link)))

  (defroute "*" [*]
    (go (<! (ensure-recipes-loaded data))
        (om/update! data :view :default))))

1 个答案:

答案 0 :(得分:2)

使用loop构造,其中没有任何(停放)通道操作等待,这完全违背了core.async的精神。请记住,JavaScript是单线程的,因此如果您不执行执行线程,则无法运行其他任何内容。

在加载操作完成后,关闭一个通道。需要阻止时尝试从该通道读取;如果它返回nil,它已完成,如果它阻止,那么你有所需的等待操作。如果您想在等待期间定期做某事,那么请从该频道和超时中读取。