Node.js API的语言转换为ClojureScript

我正在编写一个Electron应用程序,在这个应用程序中,我需要与一些Node.js API进行交互 – 读取文件,获取目录条目,监听事件。

当然,我可以用编写ClojureScript的方式编写JavaScript,但是我想知道ClojureScripts对callback式API,stream,EventEmitter的作用,以及如何编写node.js API的包装器,在ClojureScript中看起来很陌生。

再具体一点:

  1. 如何编写一个包装callback式node.js API的API。 (比如fs.readdir
  2. 我如何与类似EventEmitter的API交互?
  3. (可能接近第2页)我如何使用node.jsstreamAPI?

根据我的经验,处理这些问题最简单的方法就是使用core.async 。

callback风格

例如,阅读一个目录:

 (def fs (js/require "fs")) (defn read-dir [path] (let [out (async/chan)] (.readdir fs path (fn [err files] (async/put! (if err err files)) (async/close! out))) out)) 

我将结果传递给一个通道,即使这个结果是错误的。 这样,调用者可以通过这样做来处理错误。 例如:

 (let [res (<! (read-dir "."))] (if (instance? js/Error res) (throw res) (do-something res)) 

在我自己的项目中,我使用cljs-asynchronize ,它允许您将NodeJScallback样式函数转换为core.async兼容函数。 例如,这与第一个示例相同:

 (defn read-dir [path] (asynchronize (.readdir fs path ...))) 

最后,为了通过通道处理错误,我个人发现“error handling与Clojureasynchronous”相当有用。 所以,你可以写上面的error handling代码:

 (try (let [res (<? (read-dir "."))] (do-something res)) (catch js/Error e (handle-error e)) 

stream

streamAPI更简单:

 (defn create-read-stream [path] (let [out (async/chan) stream (.createReadStream fs path)] (.on stream "close" #(async/close! out)) (.on stream "data" #(async/put! out %)) out)) 

我认为你的问题的答案是“这取决于”。

始终考虑所有选项。 仅仅因为core.async在一个环境中是有意义的,并不是在任何地方都是最好的select。

如果只调用一次,并且不需要与其他任何协调(例如fs.readdir ),则使用正常callback是很好的。

core.async非常适合stream式传输,比如你需要获得一系列想要积累到最终结果(例如"data","data","data","close","end" )的事件链。

承诺也是另一种select。

你需要的协调越多, core.async就越有意义。 如果你不需要考虑替代scheme。