Poll with Promises
Here's an implementation for polling using an async function.
Goal
We want to call checkTheThingAgain until we get TheThing back. We're poll, meaning check this thing repeatedly, on a regular schedule until it succeeds or we run out of patience and time it out.
The implementation
checkTheThing returns a Result type that packages up the return value of operations that might fail. This isn't important to polling, but it shows how we tactically decide when to return from the poll.
In this poll implementation, we're dealing with async things. That means that the functions return Promises.
First, we immediately call the checkTheThingAgain function. No waiting.
If it fails (!result.ok), we return the failure immediately. No sense continuing to poll.
If we find the thing we're looking for (result.value), we also return immediately.
Then we have to decide: Have we polled long enough, or shall we try again.
If we still have patience to poll, we wait 1 second and then recurse and try again.
The mind-bending part is always the recursion. And in async, it's a little odder, because we need to make sure that we return a promise. But we can't just return the recursive pollTheThing call, because we need to wait first. So, instead we wrap the setTimeout call in a Promise that we instantiate manually so we can call resolve manually when the stack is popped, resolving with the value of the result, some n number of tries later.
type Result<T, E = Error> = { ok: true; value: T } | { ok: false; error: E }
type TheThing = unknown
async function pollTheThing(elapsedMs: number = 0): Promise<Result<TheThing>> {
const MAX_TRIES = 5
const INTERVAL_MS = 1000
const result = await checkTheThingAgain()
if (!result.ok) return result
if (result.value) return result
if (elapsedMs >= MAX_TRIES * INTERVAL_MS) {
return { ok: false, error: new Error('Timed out the thing') }
}
return new Promise((resolve) =>
setTimeout(async () => {
const result = await pollTheThing(elapsedMs + INTERVAL_MS)
resolve(result)
}, INTERVAL_MS),
)
}