REFERENCE / CORE API
flushSync()
Runs every pending effect now — including every DOM binding — instead of waiting for the microtask in which they would otherwise run. Also drains any onMount callbacks the flush produced.
Signature
flushSync(): void
Why it exists
A write updates a signal's value immediately but defers its effects. Almost always that is what you want: many writes, one DOM pass. The exception is code that needs to read the DOM after a write in the same task — a measurement, a scroll position, a test assertion.
count.value = 5;
el.textContent; // still the old number — the DOM effect is queued, not run
flushSync();
el.textContent; // "5"
The FLIP pattern
The textbook use: measure, mutate, flush, measure again, then animate the difference. The runtime does no animation of its own, so this is plain Web Animations on real nodes.
// measure → mutate → flushSync → measure again, in one synchronous frame
const before = row.getBoundingClientRect();
items.value = reordered;
flushSync(); // the rows have moved now
const after = row.getBoundingClientRect();
row.animate([{ transform: `translateY(${before.top - after.top}px)` }, { transform: 'none' }], 200);
flushSync vs tick
flushSync() is synchronous and forces the work. await tick() simply waits for the flush that was going to happen anyway — the right choice in async code, and the one that cannot run effects re-entrantly.
Try it
import { signal, flushSync, tick, html, mount } from '@amojs.dev/core';
const n = signal(0);
const report = signal('click a button');
let span: HTMLElement;
const withFlushSync = () => {
n.value++;
const before = span.textContent; // the value changed, the DOM has not — effects wait for a microtask
flushSync(); // run every pending effect now
report.value = `before flushSync the DOM showed ${before}, after it shows ${span.textContent}`;
};
const withTick = async () => {
n.value++;
const before = span.textContent;
await tick(); // resolves once the pending effects have run
report.value = `before tick the DOM showed ${before}, after it shows ${span.textContent}`;
};
const Demo = () => html`<div class="demo">
<p>n = <b ref=${(el: HTMLElement) => (span = el)}>${n}</b></p>
<div class="row">
<button class="counter" onclick=${withFlushSync}>n++ then flushSync()</button>
<button class="counter" onclick=${withTick}>n++ then await tick()</button>
</div>
<p class="status">${report}</p>
</div>`;
const host = document.getElementById('demo');
if (host) mount(Demo, host);