Skip to content

Instantly share code, notes, and snippets.

@bever1337
Last active June 15, 2023 05:59
Show Gist options
  • Save bever1337/e2027b6f406b78ddd4bdfb36ddc61280 to your computer and use it in GitHub Desktop.
Save bever1337/e2027b6f406b78ddd4bdfb36ddc61280 to your computer and use it in GitHub Desktop.
Functional event loops
const target = new EventTarget();
setInterval(() => {
target.dispatchEvent(new Event("event-a"));
}, 3333);
setInterval(() => {
target.dispatchEvent(new Event("event-b"));
}, 4444);
setInterval(() => {
target.dispatchEvent(new Event("event-c"));
}, 5555);
const main = (tick: number) => {
const controller = new AbortController();
Promise.race([
ofEvent("event-a", target, controller.signal),
ofEvent("event-b", target, controller.signal),
ofEvent("event-c", target, controller.signal)
])
.then((event: Event) => {
console.log(`Tick ${tick}: ${event.type}`);
})
.finally(() => {
controller.abort();
main(tick + 1);
});
};
main(0);
function ofEvent(type: string, target: EventTarget, signal: AbortSignal) {
return new Promise<Event>((resolve) => {
target.addEventListener(type, resolve, { once: true, signal });
});
}
const target = new EventTarget();
setInterval(() => {
target.dispatchEvent(new Event("event-a"));
}, 3333);
setInterval(() => {
target.dispatchEvent(new Event("event-b"));
}, 4444);
setInterval(() => {
target.dispatchEvent(new Event("event-c"));
}, 5555);
const eStream = new ReadableStream<Event>(
eventSource([
["event-a", target],
["event-b", target],
["event-c", target],
])
);
const main = (tick: number, reader: ReadableStreamDefaultReader<Event>) => {
reader
.read()
.then((result) => {
console.log(`Tick ${tick}: ${result.value?.type}`);
})
.finally(() => {
main(tick + 1, reader);
});
};
main(0, eStream.getReader());
function eventSource(
sources: [type: string, target: EventTarget][]
): UnderlyingSource<Event> {
const abortController = new AbortController();
return {
cancel() {
abortController.abort();
},
start(controller: ReadableStreamDefaultController) {
const listener = (event: Event) => {
controller.enqueue(event);
};
sources.forEach(([type, target]) => {
target.addEventListener(type, listener, {
signal: abortController.signal,
});
});
},
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment