0 day streak
javascript / intermediate
Snippet

Controlling Asynchronous Polling Streams with Async Generators in React

Async generator functions (`async function*`) offer a clean control-flow mechanism to produce streams of values over time. In React effects, consuming an async generator with a `for await...of` loop simplifies conditional polling logic and allows clean cancellation when dependencies change or the component unmounts.

snippet.js
javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import { useState, useEffect } from 'react';
async function* pollStatus(jobId, intervalMs = 2000) {
while (true) {
const res = await fetch(`/api/jobs/${jobId}`);
const data = await res.json();
yield data;
if (data.status === 'completed' || data.status === 'failed') break;
await new Promise((resolve) => setTimeout(resolve, intervalMs));
}
}
export function JobTracker({ jobId }) {
const [job, setJob] = useState(null);
useEffect(() => {
let isCancelled = false;
const generator = pollStatus(jobId);
async function consume() {
for await (const update of generator) {
if (isCancelled) break;
setJob(update);
}
}
consume();
return () => { isCancelled = true; };
}, [jobId]);
return <div>Status: {job ? job.status : 'Connecting...'}</div>;
}
react
Breakdown
1
async function* pollStatus(jobId, intervalMs = 2000) {
Declares an async generator that can yield streamed responses and pause execution between iterations.
2
yield data;
Emits the latest fetched payload to the consumer without terminating the generator loop.
3
for await (const update of generator) {
Iterates asynchronously over each value produced by the generator as promises resolve.