迭代回调地狱(在ClojureScript中)

时间:2016-01-02 23:04:26

标签: javascript node.js clojure clojurescript

1有问题的JavaScript函数

我正在处理JS中一个非常有问题的函数,该函数调用回调函数迭代次。特别是,该函数接受一个yaml字符串并为在字符串中找到的每个数量的yaml文档运行一个回调函数:

var yaml = require('js-yaml');

yaml.safeLoadAll(data, function (doc) {
  console.log(doc);
  });

所以在这里,如果data包含2个yaml文档,那么我们将在控制台中看到2个日志。

2在ClojureScript中处理它

假设string有一个未知数量的yaml文档。我想使用core.async频道将每个文档放入一个javascript数组中。

首先,我创建了一个将每个yaml文档绑定到一个频道的函数:

(defn yaml-string->yaml-chan [string]
  (let [c (chan)]
    (go 
      (.safeLoadAll 
       yaml
       string 
      (fn [current-yaml-object] 
        (go 
          (>! c current-yaml-object)
          ;(close! c) ; cant close here or we only get one doc!
        )
      ))  
    ) c ; here we return the channel
  )
)

然后我创建了一个函数,它从通道中吸取每个yaml文档并将它们粘贴到一个javascript数组中(封装在另一个通道中)。

(defn yaml-chan->array-chan [c]
  (let [arr (js/Array.) arr-chan (chan) a (atom true)]
    (go
      (reset! a (<! c))
      (while (not-nil? @a)
    (.push arr @a)
    (reset! a (<! c))
      )
      (>! arr-chan arr)
    ) arr-chan
  )
)

然后我尝试执行结果:

(go (println <! (yaml-chan->yaml-array-chan (yaml-string->yaml-chan string)))

我得到的只是#object[cljs.core.async.impl.channels.ManyToManyChannel] :(我认为它是因为我从未关闭yaml对象的原始通道。但是我如何使用该迭代回调函数执行此操作?在何处以及如何执行此操作我关闭那个频道?

2 个答案:

答案 0 :(得分:1)

我不认为core.async会在这种情况下帮助很多。这在普通的javascript中也很难。只要有更多要加载的文档,safeLoadAll就会在回调时触发。除了使用某种不稳定的超时检查之外,没有办法知道它是否已完成(这不会保证所有内容都已加载,只是在时间阈值内没有发生任何活动)

如果您不需要将所有文档收集到一个数组中,那么您可以使用core.async通道处理来处理每个结果。如果你真的需要一个数组,那么你应该找到另一个方法(循环遍历所有文档并单独加载它们),这样你就可以确定所有文件加载完成后的

答案 1 :(得分:0)

我不会让你的回调在每次调用时生成一个通道。相反,我会创建一个函数,它关闭一个你作为回调传入的通道。然后将所有文档推送到此频道,然后您可以在准备好后阅读该文档以获取文档。