Resumable: async & timers

Imperative handlers — setTimeout / setInterval — that resume without re-running the component. Key trick: non-signal state (the timer id) must live in a signal to be captured by the resumed handler scope.

Tip
The search is debounced (commits after 400ms idle). The stopwatch is driven by setInterval; the interval callback updates the reactive display every tick. Neither component runs on the client.

Debounced search


(idle)

Stopwatch


0.0s
async.tsxTSX
"use resumable";
import { signal } from "@bext-stack/framework/signals";

// Debounce: the timer id lives in a SIGNAL so it survives resume
// (a plain local would not be captured by the resumed handler scope).
const query = signal(""), typing = signal(false), timer = signal(0);
<input onInput={(e) => {
  const val = e.target.value;
  typing.value = true;
  clearTimeout(timer.value);
  timer.value = setTimeout(() => { query.value = val; typing.value = false; }, 400);
}} />

// Stopwatch: the interval callback closes over a rebound signal,
// so each tick updates the reactive display — component never runs.
id.value = setInterval(() => { tenths.value++; }, 100);