Skip to content

refactor(core): simpler after-timer dispatch, fewer per-event allocations - #71

Merged
ivanbanov merged 4 commits into
mainfrom
refactor/core-kiss
Sep 5, 2026
Merged

refactor(core): simpler after-timer dispatch, fewer per-event allocations#71
ivanbanov merged 4 commits into
mainfrom
refactor/core-kiss

Conversation

@ivanbanov

Copy link
Copy Markdown
Member

Why/What

A review pass over the core machine for simpler code and hot-path allocations. Two commits, each with a patch changeset. No behavior change for consumers.

Changes

KISS (af725ef)

  • after timers dispatch through enqueue like any send. dispatchAfter no longer runs its own copy of the flush cycle, and the queueMicrotask branch is gone (a timer cannot fire inside a synchronous drain). The stale check keeps only the entry generation, which already covers "state exited" and "state re-entered".
  • send and setContext are class-field arrows like start and stop. doSend and the notify wrapper are removed.
  • One frozen INIT_EVENT instead of a fresh boot event per use.
  • oneOf picks its branch with a loop instead of find.

Perf (6aa4c3f)

  • runActions and resolve run a single entry directly, no one-item array wrap per event.
  • resolve owns all three entry forms and builds guard params only when a guard is met. The per-event resolver closure and the selectTransition fast path in the machine are gone.
  • Action host and computed host hold the live ctx and computed objects. No getter call per read, including inside the computed tracking proxies and stale().
  • Connector builds the connect() argument once. shallowEqual compares props with two for..in passes instead of two Object.keys arrays.

Same-session A/B against the KISS commit:

Case Before After
Single event 14.97 M 16.1 M (+7%)
State churn, entry and exit fn 8.88 M 9.8 M (+10%)
Guards, 8 and 32 candidates 4.65 M / 3.48 M 4.8 M / 3.4 M (flat)

Full suite, typecheck, lint and format pass. Documented benchmark tables are unchanged: the headline rows moved within noise.

Open point for review: the shallowEqual rewrite in connector.ts is the one change that adds a little subtlety (key counter) without a measured gain. Happy to drop it back to Object.keys if you prefer.

Issues

None.

🤖 Generated with Claude Code

ivanbanov and others added 2 commits September 3, 2026 13:40
- `after` timers dispatch through `enqueue` like any send; the private
  flush cycle and the unreachable microtask branch in `dispatchAfter` are
  gone, and the stale check keeps only the entry generation
- `send` / `setContext` are class-field arrows; `doSend` and the `notify`
  wrapper are removed; the action host gets the bound fields directly
- one frozen `INIT_EVENT` instead of a fresh boot event per use
- `oneOf` picks its branch with a loop instead of `find`

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- runActions / resolve run a single entry directly, no one-item array wrap
- resolve builds guard params lazily and takes the action host, so the
  per-event resolver closure and selectTransition fast path are gone
- action host and computed host hold the live ctx/computed objects; no
  getter call per read (computed proxy reads and stale() checks included)
- connector builds the connect() argument once; shallowEqual compares
  props with two for..in passes, no key arrays

Single event +7%, state churn +10%, guard fallthrough unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
dunky-state-machine Ready Ready Preview Sep 5, 2026 2:47pm UTC

`flushing` was the only "flush"; the method, the dev limit, the error text
and the spec all said "drain". Align on flush: `flushQueue`, `MAX_FLUSH`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Column padding was left over from the dropped POLA row (#69); oxfmt --check
failed on main because of it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@ivanbanov
ivanbanov merged commit ff3368c into main Sep 5, 2026
8 checks passed
@ivanbanov
ivanbanov deleted the refactor/core-kiss branch September 5, 2026 14:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant