Skip to content

waitFor()

Eugene Lazutkin edited this page Jul 30, 2026 · 1 revision

Description

The waitFor() function polls a predicate until it returns a truthy value — a bounded condition poller for code that waits on eventual conditions: a server accepting connections, a file appearing, async state settling. It replaces hand-rolled sleep loops, which are flaky when the sleep is short and slow when it is long.

Key features

  • Accepts synchronous and asynchronous predicates.
  • Resolves with the first truthy predicate result (the value, not just true).
  • Optional timeout rejects the wait with an Error.
  • Optional AbortSignal rejects the wait with signal.reason.
  • A predicate that throws (or rejects) rejects the wait with that error.

Technical specifications

waitFor is available as a named and default export.

const value = await waitFor(predicate, {timeout, interval, signal});
  • Input: predicate (() => T | Promise<T>) — the condition to poll. It is called immediately, then every interval milliseconds after the previous check settles.
  • Options (all optional):
    • timeout (number) — reject after this many milliseconds; no timeout when omitted.
    • interval (number) — the polling period in milliseconds. Default: 50.
    • signal (AbortSignal) — reject with signal.reason when aborted.
  • Output: a Promise<T> that resolves with the first truthy predicate result.

Usage Instructions

import waitFor from 'time-queues/wait-for.js';

// Wait for a server to accept connections, checking twice a second, giving up after 10s
await waitFor(
  () =>
    fetch(url).then(
      r => r.ok,
      () => false
    ),
  {timeout: 10_000, interval: 500}
);

// Wait for async state to settle in a test, tied to the test's abort signal
const user = await waitFor(() => store.currentUser, {signal: t.signal});

The caller is responsible for sane option values — the library does not validate them.

Troubleshooting

  • The wait never resolves: the predicate never returns a truthy value — add a timeout or a signal to bound the wait.
  • Distinguishing timeout from abort: a timeout rejects with a plain Error; an abort rejects with signal.reason (an AbortError DOMException by default).
  • Predicate slower than the interval: checks never overlap — the next poll is scheduled only after the previous check settles.

See Also

  • sleep() — promise-based delay
  • Scheduler — time-based scheduling
  • batch() — run async ops with concurrency limit

Clone this wiki locally