Chapter 01 @dirtytalk/engine
Mark. Coalesce. Flush.
Everything in dirtytalk runs on one small loop: a channel collects what changed, a scheduler picks when, and only the subscribers who care get told. This stage runs the real @dirtytalk/engine.
01
Something changed.
A mutation calls channel.mark(region). Here a region is a set of keys.
With SyncScheduler the channel flushes right away, and the
Avatar, which cares about users, wakes up.
channel.mark(new Set(['users'])); 02
Marks coalesce.
Six marks land in one task. With MicrotaskScheduler they union into a
single dirty region, and the channel flushes once at the end of the task.
Watch the timeline: six marks below, one flush above.
03
Only who cares.
Every subscriber declares an interest region. On flush, the channel intersects it with
the dirty region and skips the rest. Nobody listens to route, so marking
it wakes no one. theme wakes only the toggle.
channel.subscribe(
() => new Set(['theme']),
(dirty) => repaintToggle(),
); 04
You choose when.
Real marks arrive from many tasks: clicks, timers, sockets. A microtask flush runs at
the end of each task, so a storm of separate tasks still flushes once per mark.
Switch to RAFScheduler and everything that lands before the next frame
flushes together.
05
Or hold the flush.
ManualScheduler waits for you. Marks pile up as pending keys in the channel
until .pump() flushes them all at once. It's handy in tests and in your
own frame loop. The hero on the home page pumps its scene this way.
06
Your turn.
Click a key to mark it, switch schedulers, set off a burst or a storm, and watch the counts underneath: marks in, flushes out, wakes only where interest meets dirt.
channel.mark()
DirtyChannel
- users
- theme
- cart
- route
subscribe()
users 0 wakes
theme 0 wakes
cartusers 0 wakes
0 marks → 0 flushes → 0 wakes