v135 · dom
Performance benchmark
Mutation Events fire synchronously during every DOM mutation, blocking the call stack. MutationObserver batches records and delivers them asynchronously after the microtask queue drains. This benchmark shows the difference: Mutation Events fire once per node inserted, MutationObserver fires once per batch regardless of how many nodes were inserted.
Mutation Events in Chrome 135: checking…
Benchmark settings
Mutation Events (deprecated)
Time (ms)
—
Callbacks fired
—
Delivery
synchronous
Blocked DOM
yes — per-node
MutationObserver (modern)
Time (ms)
—
Callbacks fired
—
Delivery
async batched
Blocked DOM
no — batch
Performance comparison
Event log
last 50 entries
Run the benchmark to see events…
// Mutation Events fire synchronously — one callback per node
const container = document.getElementById('container');
container.addEventListener('DOMNodeInserted', e => {
callbackCount++; // fires N times for N insertions
});
const t0 = performance.now();
for (let i = 0; i < N; i++) {
container.appendChild(document.createElement('div')); // callback fires HERE
}
const t1 = performance.now(); // DOM blocked for entire insertion loop
// MutationObserver batches — one callback for ALL insertions
const observer = new MutationObserver(records => {
callbackCount++; // fires 1 time regardless of N
// records.length === N
});
observer.observe(container, { childList: true });
const t0 = performance.now();
for (let i = 0; i < N; i++) {
container.appendChild(document.createElement('div')); // no callback yet
}
const t1 = performance.now(); // DOM loop completes unblocked
// callback fires later in the microtask queue