Skip to content

Instantly share code, notes, and snippets.

@denchiklut
Created February 16, 2026 19:40
Show Gist options
  • Select an option

  • Save denchiklut/86fabedcceecb276c83d764a71e1f776 to your computer and use it in GitHub Desktop.

Select an option

Save denchiklut/86fabedcceecb276c83d764a71e1f776 to your computer and use it in GitHub Desktop.
AsyncIterator
type Emit<T> = (value: T) => void;
type Subscribe<T> = (emit: Emit<T>) => void | (() => void);
export async function* toAsyncIterator<T>(subscribe: Subscribe<T>): AsyncGenerator<T> {
const queue = new AsyncQueue<T>();
const cleanup = subscribe(v => queue.push(v));
try {
while (true) {
yield queue.next();
}
} finally {
cleanup?.();
}
}
export class AsyncQueue<T> {
private buffer: Array<{ value: T }> = [];
private pending: Array<(item: { value: T }) => void> = [];
push(value: T) {
const next = this.pending.shift();
if (next) return next({ value });
this.buffer.push({ value });
}
async next(): Promise<T> {
const item = this.buffer.shift();
if (item) return item.value;
return new Promise<T>(resolve => {
this.pending.push(({ value }) => resolve(value));
});
}
}
async function main() {
const interval = setInterval(() => console.log('tick', Date.now()), 100);
const iter = toAsyncIterator<number>(emit => {
let i = 0;
const id = setInterval(() => emit(++i), 500);
return () => clearInterval(id);
});
for await (const value of iter) {
console.log('yielded:', value);
if (value >= 3) break;
}
clearInterval(interval);
console.log('done');
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment