Core.async: Take all values from collection of promise-chans
考虑这样的数据集:
1 2 3 4 | (def data [{:url"http://www.url1.com" :type :a} {:url"http://www.url2.com" :type :a} {:url"http://www.url3.com" :type :a} {:url"http://www.url4.com" :type :b}]) |
这些URL的内容应并行请求。根据项目的:type值,这些内容应由相应的函数解析。一旦所有响应到达,解析函数将返回集合,该集合应该被串联。
因此,我们假设存在函数
看来
这是一个代码草图,我正在使用基于回调的
1 2 3 4 5 6 7 8 9 10 11 12 | (defn f [data] (let [chans (map (fn [{:keys [url type]}] (let [c (promise-chan (map ({:a parse-a :b parse-b} type)))] (http/get url {} #(put! c %)) c)) data) result-c (promise-chan)] (go (put! result-c (concat (<! (nth chans 0)) (<! (nth chans 1)) (<! (nth chans 2)) (<! (nth chans 3))))) result-c)) |
结果可以这样读取:
1 | (go (prn (<! (f data)))) |
我想说
因此,如果坚持使用
1 2 3 4 5 | ... (let [c (chan 1 (map ({:a parse-a :b parse-b} type)))] (http/get url {} #(do (put! c %) (close! c))) c) ... |
至此,您正在使用封闭通道,事情变得更简单了。要收集所有值,您可以执行以下操作:
1 2 3 4 5 6 7 8 | ;; (go (put! result-c (concat (<! (nth chans 0)) ;; (<! (nth chans 1)) ;; (<! (nth chans 2)) ;; (<! (nth chans 3))))) ;; instead of above, now you can do this: (->> chans async/merge (async/reduce into [])) |
UPD(以下是我的个人意见):
似乎,使用
如果仍然有人在看这个,请添加@OlegTheCat的答案:
您可以使用单独的渠道处理错误。
1 2 3 4 5 6 7 8 9 10 11 12 | (:require [cljs.core.async :as async] [cljs-http.client :as http]) (:require-macros [cljs.core.async.macros :refer [go]]) (go (as-> [(http/post <url1> <params1>) (http/post <url2> <params2>) ...] chans (async/merge chans (count chans)) (async/reduce conj [] chans) (async/<! chans) (<callback> chans))) |
我也需要此功能,因为我真的很喜欢
1 2 3 4 5 | (defmacro <<? [chans] `(let [res# (atom [])] (doseq [c# ~chans] (swap! res# conj (serverless.core.async/<? c#))) @res#)) |
如果您想查看该功能的完整上下文,请访问GitHub。灵感来自David Nolen的博客。
在
1 2 3 4 5 6 7 8 9 | (let [result (chan)] (pipeline-async 20 result (fn [{:keys [url type]} ch] (let [parse ({:a parse-a :b parse-b} type) callback #(put! ch (parse %)(partial close! ch))] (http/get url {} callback))) (to-chan data)) result) |