promesa icon indicating copy to clipboard operation
promesa copied to clipboard

Support for AsyncIterator

Open chr15m opened this issue 2 years ago • 2 comments

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?

chr15m avatar Jan 22 '24 12:01 chr15m

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))

borkdude avatar Oct 10 '25 09:10 borkdude

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

borkdude avatar Oct 10 '25 09:10 borkdude