使用core.async

时间:2017-02-08 18:49:01

标签: clojurescript core.async

我有一个Clojurescript项目,我需要阻止整个线程执行,直到发生DOM事件。

在这种情况下,事件是DOMContentLoaded,它在初始HTML文档被完全加载和解析时触发。但它可以扩展到任何DOM(或非DOM)事件。

由于我是Clojurescript和async的新手,我不知道如何解决这个问题。我的第一个猜测是使用core.async库。在一些文档抓取之后,我带来了这个功能:

(defn wait-dom-loading
  []
  (let [c (async/chan)]
 {1} (.addEventListener js/document "DOMContentLoaded" (fn [] (async/go (async/>! c true))))
 {2} (async/go (async/<! c))))

我理解的方式是{2} chan c 获取并停放,直到{1}中的侦听器评估该函数并且 puts < / em> chan c 中的值。

由于我几乎不了解如何对异步代码进行单元测试(除了将其置于(async done)表达式中并在完成时调用done)我无法验证我所做的是否正确。我试过这个片段:

(do
  (wait-dom-loading)
  (-> (dommy/sel1 :p)
      (dommy/set-text! "Loaded !")))

在html页面中有一个 p 块,并注意到控制台抱怨js代码试图操纵一个尚不存在的DOM对象。这证实我所做的并没有按计划运作。

  1. 这个例子似乎有什么不妥?
  2. 这有点矫枉过正吗?我可以通过更小的解决方案解决这个问题,甚至喘息内置功能吗?
  3. 将我的脚本放在我的html页面底部是不是很糟糕的做法?
  4. 由于这是我关于堆栈溢出的第一个问题,我希望它写得很好。

1 个答案:

答案 0 :(得分:0)

我会这样做:

(ns domevent.core
    (:require [cljs.core.async :as async :refer [chan]])
    (:require-macros [cljs.core.async.macros :refer [go]]))

(enable-console-print!)    
(def ch (chan))

(go
    (pr "i am waiting")
    (pr (<! ch))
    (dommy/set-text! (dommy/sel1 :p) "Loaded !"))

(.addEventListener js/document "DOMContentLoaded" (fn [] (go (>! ch "hello"))))

或更简单:

(let [ch (chan)]
    (go
        (pr "i am waiting")
        (<! ch)
        (dommy/set-text! (dommy/sel1 :p) "Loaded !"))

    (.addEventListener js/document "DOMContentLoaded" #(close! ch)))
)

这里的要点是ch,由读者和作者共享。当(<! ch)发生时,ch中没有任何内容,因此该线程被停放(即停止并等待ch中出现的任何内容)。同时,DOMContentLoaded发生,处理程序写入通道。然后前一个线程继续。