我有一个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对象。这证实我所做的并没有按计划运作。
由于这是我关于堆栈溢出的第一个问题,我希望它写得很好。
答案 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发生,处理程序写入通道。然后前一个线程继续。