我在Clojurescript中,尝试使用core.async
从本机Javascript函数(我在浏览器中)获取结果,并有条件地将其集成到地图中。
我有一个函数来包装本机浏览器调用(受Timothy Baldridge's talk on core.async启发,感兴趣的人约34分钟):
(defn geolocation []
(let [c (chan)
cb (fn [e] (put! c (js->clj e)))]
(if (exists? js/navigator.geolocation)
(.getCurrentPosition js/navigator.geolocation. cb cb)
(put! c {:error "Geolocation is not supported"}))
c))
我可以这样使用它:
;; this works
(go (.log js/console "RES1 -" (<! (geolocation))))
;; this too (not sure how to print it though)
(go (println "RES2 - " (-> {}
(assoc :test (<! (geolocation))))))
;; this fails... why ?
(go (println "RES3 - " (-> {}
(#(when true
(assoc % :test (<! (geolocation))))))))
最后一个示例失败并显示错误:Uncaught Error: <! used not in (go ...) block
,即使我认为我使用了相同类型的结构。
我做错了什么?
注意:我要求:require-macro
指令like described here正确使用。
答案 0 :(得分:2)
go
宏将获取它所提供的正文,并将所有<!
和alt!
和>!
调用转换为状态机。但它不会走进功能:
couldn't use for loop in go block of core.async?
通过在函数边界处停止转换,我的意思是:go块占用它的主体并将其转换为状态机。对
<!
>!
或alts!
(以及其他一些)的每次调用都被视为状态机转换,其中块的执行可以暂停。在每个点上,机器变成回调并连接到通道。当此宏到达fn表单时,它将停止翻译。因此,您只能从go块内部调用<!
,而不是在代码块内的函数内部。这是
core.async
魔力的一部分。没有go
宏,core.async代码看起来很像其他语言中的回调地狱。