我无法按照创建顺序从浏览器中的core.async频道返回值(而不是返回值的顺序)。通道本身是从映射cljs-http.client / get返回的URL列表返回的。
如果我在let
块中手动绑定结果,那么我可以按照通道的顺序返回结果"手动",但这显然是一个问题,当我没有'知道存在多少个频道。
(let [response-channels (map #(http/get "http://date.jsontest.com" {:with-credentials? false}) (range 3))]
; Response is now three channels generated by http/get:
;(#object[cljs.core.async.impl.channels.ManyToManyChannel]
; #object[cljs.core.async.impl.channels.ManyToManyChannel]
; #object[cljs.core.async.impl.channels.ManyToManyChannel])
; If I want the results back in the guaranteed order that I made them, I can do this:
(go (let [response1 (<! (nth response-channels 0))
response2 (<! (nth response-channels 1))
response3 (<! (nth response-channels 2))]
(println "This works as expected:" response1 response2 response3))))
但是,如果我尝试在频道上映射<!
而不是单独绑定它们,那么我只会得到一个频道列表而不是它们的值。
(let [response-channels (map #(http/get "http://date.jsontest.com" {:with-credentials? false}) (range 3))]
(let [responses (into [] (map (fn [c] (go (<! c))) response-channels))]
(println "This just returns the channels:" responses)
; This is still just a vec of many-to-many channels
; [#object[cljs.core.async.impl.channels.ManyToManyChannel]
; #object[cljs.core.async.impl.channels.ManyToManyChannel]
; #object[cljs.core.async.impl.channels.ManyToManyChannel]]
)
)
我怀疑go
块的位置存在问题,但我无法将其移出匿名函数,而不会出现我使用{{1}的错误在<!
块之外。
这不起作用:
go
这两点都没有:
(into [] (go (map <! response-channels)))
我还尝试通过(go (let [responses (into [] (map <! response-channels))]))
合并频道,然后使用async/merge
来结合值,但结果按照请求完成的顺序排列,而不是合并频道的顺序。< / p>
任何人都可以根据频道列表中存在的频道从频道列表中检索值吗?
答案 0 :(得分:4)
在Clojure中你可以做(map <!! response-channels)
,但这在ClojureScript中是不可能的。更重要的是,它不鼓励使用map
- 或一般的懒惰操作 - 用于副作用(结帐this blog post以查明原因)。您的代码未能产生您期望的结果的原因是fn
块中go
的(嵌套)使用(请参阅this answer):
通过[Clojure go-block]在函数边界处停止转换,我的意思是:go块占用它的主体并将其转换为状态机。对
<!
>!
或alts!
(以及其他一些)的每次调用都被视为状态机转换,其中块的执行可以暂停。在每个点上,机器变成回调并连接到通道。当此宏达到fn
格式时,会停止翻译。因此,您只能从go块内部调用<!
,而不是在代码块内的函数内部。
我不太确定,但是当你看到(source map)
时,你会看到它直接调用fn
以及通过其他函数调用lazy-seq
。 1}}),这可能是(go (map <! response-channels))
无效的原因。
无论如何,doseq
:
(go (doseq [c response-channels]
(println (<! c))))
这将尊重response-channels
内的订单。