export class AsyncQueue implements AsyncIterable { private queue: T[] = [] private resolvers: ((value: T) => void)[] = [] push(item: T) { const resolve = this.resolvers.shift() if (resolve) resolve(item) else this.queue.push(item) } async next(): Promise { if (this.queue.length > 0) return this.queue.shift()! return new Promise((resolve) => this.resolvers.push(resolve)) } async *[Symbol.asyncIterator]() { while (true) yield await this.next() } } export async function work(concurrency: number, items: T[], fn: (item: T) => Promise) { const pending = [...items] await Promise.all( Array.from({ length: concurrency }, async () => { while (true) { const item = pending.pop() if (item === undefined) return await fn(item) } }), ) }