# on every

> `on every (TimeSpan.FromSeconds(5)) { … }` runs a block on a repeating cadence for as long as the component is mounted. Unlike `on frame` it is driven by the wall clock rather than the display, so it keeps running when the tab is hidden and costs nothing between ticks — it is the hook for a poll, a counter or any "do this again in N seconds". A component may declare as many as it likes, each with its own cadence.

<!-- id: ui-cadence · area: ui · stability: stable · html: https://osysharp.com/reference/ui/cadence/ -->

## Summary        {#summary}
`on every (<TimeSpan>) { … }` is a component **cadence hook**: the runtime runs the block over and over, on the
interval you name, for as long as the component is mounted. It belongs to the **`on <event>`** family alongside
[on mount / on unmount](https://osysharp.com/reference/ui/lifecycle/)'s `on mount` / `on unmount` and the reactive `on change`.

It is an *auto-invoked action*, so it can do everything an action can — assign fields, create rows with
`new Entity{ … }`, and **call server functions**. That last one is most of the point: "refresh this from the server
every thirty seconds" is the canonical cadence.

```osy syntax
component Dashboard() {
  int seconds = 0;

  on every (TimeSpan.FromSeconds(1)) { seconds = seconds + 1; }

  render { Text($"up for {seconds}s"); }
}
```

## Signature      {#signature}
```osy syntax
on every (<TimeSpan>) { <statements> }                // the common form
on every (<TimeSpan>) (int elapsed) { <statements> }  // …plus how many intervals passed since the last run
```

The interval is a **`TimeSpan`**, never a bare number — `TimeSpan.FromSeconds(5)`,
`TimeSpan.FromMilliseconds(250)`, `TimeSpan.FromMinutes(1)`. A plain `500` is refused, because nothing in the source
would say whether it meant milliseconds or seconds and the two are a thousand-fold apart.

The hook is **anonymous**, and — uniquely — a component may declare **more than one**.

## Description    {#description}
The runtime arms a timer for the interval you named. When it fires it runs the block, and only once the block has
**returned** does it re-read the interval and arm the next one — so a body slower than its own cadence runs
back-to-back instead of stacking copies of itself, and a body that awaits a server call holds the clock while it
waits.

Because it is driven by the wall clock rather than the display, a hidden tab does not stop it: the browser may
throttle the timer, but time still passes and the missed intervals are reported to the next run (see
[missed ticks are coalesced](#elapsed)). That is the property that makes it right for a poll and wrong for an animation, and the
reverse of `on frame` — see [on every or on frame?](#versus).

### Several clocks in one component    {#several}
Each `on every` block is its own independent clock. This is the ordinary case, not an exotic one:

```osy title="a frame clock and two on-every clocks, side by side" syntax
component Monitor() {
  int frames = 0;
  int fps = 0;
  live var rows = Reading.ToList();

  on frame (double dt) { frames = frames + 1; }
  on every (TimeSpan.FromMilliseconds(500)) { fps = frames * 2; frames = 0; }   // a display counter
  on every (TimeSpan.FromSeconds(30)) { rows.Refresh(); }                       // a server poll

  render { Text($"{fps} fps"); }
}
```

A clock's identity is **where it is declared**, not the interval it happens to hold — so two blocks that name the same
interval are still two clocks, and changing an interval retimes the existing clock rather than creating a new one.

Here is a whole page that compiles — one counter on a one-second clock, a second clock at a different cadence, and a
[`on mount`](https://osysharp.com/reference/ui/lifecycle/) beside them, so the three hooks are seen coexisting rather than described:

```osy title="two clocks and a mount hook" test app=ui-cadence
[Page("/uptime")]
[Render(CSR)]
component UptimePage() {
  int seconds = 0;
  int minutes = 0;
  string label = "";

  on mount { label = "counting"; }

  on every (TimeSpan.FromSeconds(1)) { seconds = seconds + 1; }
  on every (TimeSpan.FromMinutes(1)) { minutes = minutes + 1; }

  render {
    Stack(gap: 2) {
      Text($"{label}: {seconds}s");
      Text($"{minutes} minute(s)");
    }
  }
}
```

### Can the interval depend on state?   {#computed}
The interval is an ordinary **expression**, re-read on each tick, so a cadence can depend on state:

```osy syntax
component Game() {
  int level = 1;

  // Every ten levels takes a slice off the interval — the piece falls faster as you play.
  on every (TimeSpan.FromSeconds(0.75 - (level - 1) * 0.06)) { StepDown(); }
}
```

A change takes effect at the **next** tick: the interval already in flight runs to completion, then the clock re-reads
and re-arms. Nothing cancels a pending tick early.

### What happens to a tick that was missed?   {#elapsed}
A page that could not keep up — a stalled tab, a body slower than its own interval — does **not** accumulate a queue of
runs. The missed intervals are **coalesced into the next run**, which is told how many there were:

```osy syntax
on every (TimeSpan.FromSeconds(1)) (int elapsed) {
  clock = clock + elapsed;      // count the time that really passed, not the ticks that really fired
}
```

`elapsed` is `1` on an ordinary tick and higher only when the page fell behind. This is why there is no "what happens
on overrun?" setting: **ignoring `elapsed` skips the backlog, and looping over it catches up** — the choice is a line
of your code rather than a mode. It is the same shape `Schedule` uses for a missed server job, which records one
occurrence carrying the number it absorbed.

The next tick is armed only after the body **returns** — including a body that awaited a server call — so a slow body
runs back-to-back rather than stacking copies of itself.

## `on every` or `on frame`?    {#versus}
Both repeat; they are for different things and neither substitutes for the other.

| | `on frame (double dt)` | `on every (TimeSpan)` |
|---|---|---|
| driven by | the **display** (~60 times a second) | the **wall clock**, on your interval |
| hidden tab | **pauses** — the display is not drawing | **keeps running** (the browser may throttle it) |
| can reach the server | no | **yes** |
| how many per component | one | as many as you like |
| for | animation, physics, anything per-frame | polls, counters, "again in N seconds" |

Choose `on frame` when the answer to "how often?" is *"every time the screen updates"*. Choose `on every` for
everything else — a five-minute poll on the frame clock would wake sixty times a second to do nothing 17,999 times out
of 18,000, and a poll on the frame clock silently stops the moment the reader switches tabs.

## Examples       {#examples}

The canonical cadence — refresh from the server on an interval, and a second clock at a different rate on the same
component, which is the part that has no equivalent in `on frame`:

```osy test app=ui-cadence
entity Reading { int Value; }

[AllowAnonymous]
int Latest() { return Reading.OrderByDescending(r => r.Value).Select(r => r.Value).FirstOrDefault(); }

[Page("/dashboard")]
[AllowAnonymous]
component Dashboard() {
  int latest = 0;
  int seconds = 0;

  // Reaches the SERVER — the whole point of the wall-clock hook.
  on every (TimeSpan.FromSeconds(30)) { latest = Latest(); }

  // A second clock, its own cadence. `elapsed` is 1 on an ordinary tick and higher only if the page fell behind,
  // so counting it rather than counting ticks keeps the number honest across a stalled tab.
  on every (TimeSpan.FromSeconds(1)) (int elapsed) { seconds = seconds + elapsed; }

  render {
    Stack(gap: 2) {
      Text($"latest {latest}");
      Text($"up {seconds}s");
    }
  }
}
```

## Limits — the clock runs on the client   {#notes}
- The hook runs on the **client**. A cadence that must survive the page being closed is a server concern — declare a
  `Schedule` instead, which is durable and operator-editable.
- A body that **throws** stops that clock and logs the error. Only that one: a broken counter does not take the poll
  beside it down.
- The clock is disposed with the component, so navigating away stops it.

## See also       {#see-also}
- [on mount / on unmount](https://osysharp.com/reference/ui/lifecycle/) — `on mount`, `on unmount` and the per-frame `on frame`
- [on change](https://osysharp.com/reference/ui/on-change/) — the *reactive* sibling: run a block when a value changes, rather than when time passes
- [The reactivity & lifecycle model](https://osysharp.com/reference/ui/reactivity/) — how a field a cadence writes reaches the screen
