Support for AsyncIterator
Occasionally an API requires the use of a JavaScript async for over some iterator like this:
for await (const [key, value] of this.keyv.iterator()) {
console.log(key, value); // Return: key and value
};
It would be neat if there was a way to do this directly in promesa, similar to the macro at How to work with asynciterable. Here's the macro:
(defmacro async-doseq [[binding async-iterable] & body]
`(let [async-iterator# ((js* "~{}[Symbol.asyncIterator]" ~async-iterable))]
(fn handle-next# []
(let [next# (.next async-iterator#)]
(.then
next#
(fn [res#]
(if (.- res# done)
nil
(do (let [~binding (.- res# value)]
~@body)
(handle-next#)))))))))
Is this something Promesa is interested in supporting?
I figured out how to do it in SCI with the existing promesa stuff, but I agree it would be nice to support this in promesa:
(def my-fn (js/Function "return (async function* makeAsyncIterable() {
for (let i = 1; i <= 3; i++) {
await new Promise(r => setTimeout(r, 1000));
yield i;
}
})"))
(def async-generator ((my-fn)))
(defn iterate [generator]
(let [iter (.call (unchecked-get generator js/Symbol.asyncIterator) generator)
results (atom [])]
(js/console.log iter)
(p/loop []
(p/let [v (.next iter)]
(if (.-done v) @results
(do
(js/console.log (.-value v))
(swap! results conj (.-value v))
(p/recur)))))))
(p/let [my-values (iterate async-generator)]
(prn my-values))
Perhaps we can support this in the existing doseq when metadata on the binding value is :async or so?
(doseq [i ^:async foo] ..)
Perhaps the metadata should go somewhere else. Open issue for squint with a similar idea:
https://github.com/squint-cljs/squint/issues/594