在ClojureScript中实现await式调用的惯用方法是什么?
在ClojureScript中实现类JavaScript
await 的异步语法 完全懂你不想为这种简单串行异步流程引入core.async的想法——它确实更适合复杂的异步编排场景,有点大材小用了。下面是几种实现你期望语法的实用方案:
1. 先把回调式API转成Promise
这是实现类await语法的基础,因为ClojureScript原生支持ES6 Promise,我们可以把回调风格的函数包装成返回Promise的版本:
比如你有一个JS回调函数:
function asyncFunction1(arg, callback) { // 异步操作完成后调用 callback(err, result) }
在ClojureScript里包装成Promise版本:
(defn async-function1 [arg] (js/Promise. (fn [resolve reject] (asyncFunction1 arg (fn [err res] (if err (reject err) (resolve res)))))))
2. 用宏实现await语法糖
你提到的0.1.0-SNAPSHOT库应该是类似轻量级的await宏工具,我们也可以自己写一个简单的宏来实现核心功能,或者直接用现成库。
自定义基础宏
如果自己写,核心宏可以这样实现:
(defmacro await [promise-expr] `(.then ~promise-expr (fn [res#] res#)))
要支持let里的串行调用,我们可以再封装一个顶层宏:
(defmacro do-async [& body] (if (empty? body) nil (let [first-step (first body) rest-steps (rest body)] `(.then ~first-step (fn [res#] (let [~'await (fn [p#] (.then p# (fn [r#] r#)))] ~@rest-steps))))))
然后就能像你期望的那样写代码了:
(try (do-async (async-function1 "foo") (let [a await b (await (async-function2 "bar" a))] ;; 这里写你的业务逻辑 (println "最终结果:" b))) (catch :default e ;; 统一错误处理 (println "出错了:" e)))
使用现成轻量级库
如果用你找到的那个0.1.0-SNAPSHOT库,引入依赖后直接就能用更简洁的写法,和你预想的完全一致:
(try (let [a (await (async-function1 "foo")) b (await (async-function2 "bar" a))] ;; 执行你的逻辑 ) (catch :default e ;; 错误处理 ))
关键注意点
- 所有回调式API必须先转成Promise,这是语法糖能工作的前提
await本质是宏,会把代码转成Promise的.then()链,完全规避嵌套回调try/catch可以直接捕获Promise的reject错误,和JS里try/await/catch的行为完全一致
内容的提问来源于stack exchange,提问作者dilvan
相关产品推荐
相关产品推荐

