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.
- Import the published @askrjs/askr/fx entrypoint.
- Keep fx timing utilities configuration next to the component, route, or server composition root that owns it.
- 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.