FX Timing Utilities
FX Timing Utilities: published entrypoints, signatures, and the constraints around them.
Example
Use the FX helpers for lifecycle-owned timing, pass cleanup through the owning scope, and replace real clocks with deterministic scheduling in tests.
import { debounceEvent, retry, timeout } from '@askrjs/askr/fx';
const search = debounceEvent(200, (event) => {
const query = (event.currentTarget as HTMLInputElement).value;
void loadResults(query);
});
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
debounceEvent(ms, handler, options?) coalesces DOM events and returns a cancelable listener with flush(). throttleEvent(ms, handler, options?) limits how often an event handler runs. For ordinary function calls, throttle(fn, ms, options?) returns a cancelable rate-limited function; @askrjs/askr/fx does not export a general debounce() helper. raf(fn) coalesces calls into one animation frame and returns a cancelable function, while scheduleTimeout(ms, fn) and scheduleIdle(fn, options?) return cancel functions for delayed or low-priority work.
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
throttle() and raf() return cancelable functions. debounceEvent(ms, handler) and throttleEvent(ms, handler) return cancelable event listeners; debounceEvent() also exposes flush(). scheduleTimeout() and scheduleIdle() return cancel functions, while scheduleRetry() returns both a cancel method and a result promise. When these helpers are called from a mounted component's task, watch callback, or event handler, Askr also cancels their pending work when that component is cleaned up.