Askr
Reference

FX Timing Utilities

Use fx timing utilities with the current published Askr packages.

  • @askrjs/askr/fx0.0.59

How to use fx timing utilities

Use the FX helpers for lifecycle-owned timing, pass cleanup through the owning scope, and replace real clocks with deterministic scheduling in tests.

  1. Import the published @askrjs/askr/fx entrypoint.
  2. Keep fx timing utilities configuration next to the component, route, or server composition root that owns it.
  3. Handle pending, unavailable, cancellation, and failure states, then verify the production path.
import { debounce, retry, timeout } from '@askrjs/askr/fx';

const search = debounce((query: string) => loadResults(query), 200);
const project = await retry(() => loadProject(id), { maxAttempts: 3 });
await timeout(1_000);

Clock contract

@askrjs/askr/fx is a pure, framework-independent set of async helpers — nothing in this subpath reads component state or lifecycle, so every function here works the same whether or not you're inside a render. `timeout(ms)` is the simplest building block: a promise-based delay you can `await` directly in tests or async flows.

Scheduling

`debounce(fn, ms, options?)` coalesces rapid calls and fires after the delay settles (useful for text input or resize handlers), while `throttle(fn, ms, options?)` caps the call rate and supports `leading`/`trailing` firing. `raf(fn)` coalesces updates into a single animation frame, `idle(fn, options?)` schedules low-priority work via `requestIdleCallback` (falling back to `setTimeout`), and `defer(fn)` runs on the microtask queue — more reliable than `setTimeout(fn, 0)` for run-after-current-stack logic.

Deterministic tests

`once(fn)` guards against double execution — handy for init logic that a test might trigger twice by accident — and `retry(fn, options?)` retries an async function with configurable `maxAttempts`, `delayMs`, and a custom `backoff(attemptIndex)` function. Because these helpers don't touch component internals, you can unit test them directly with fake timers without mounting anything.

Cleanup

The scheduling helpers — `debounce`, `throttle`, `raf` — all return a function augmented with `.cancel()`, so any pending invocation can be stopped explicitly, typically from a component's cleanup path. The event-oriented variants (`debounceEvent`, `throttleEvent`, `rafEvent`, `scheduleTimeout`, `scheduleIdle`, `scheduleRetry`) mirror this: each returns a handle with `cancel()` (and `debounceEvent` also exposes `flush()`) so you can tear down timers deterministically instead of letting them fire after a component is gone.