0

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

相关代码如下(也可作为 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))))
4

1 回答 1

2

使用loop内部没有任何(停车)通道操作的构造来等待几乎完全违背了 core.async 的精神。请记住,JavaScript 是单线程的,因此如果您不停止执行线程,则其他任何东西都没有机会运行。

在加载操作完成时关闭一个频道。当您需要阻止时,尝试从该频道读取;如果它返回nil,它就完成了,如果它阻塞,那么你就有了等待的操作。如果您想在等待时定期执行某些操作,请从该通道和超时中读取。

于 2014-06-30T15:37:53.027 回答