You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Async mode takes at least 4ms per iteration in browsers because of setTimeout clamping #709
In async mode, each iteration of the diff loop runs in a setTimeout(fn, 0) that the previous iteration scheduled. Browsers clamp nested timers to at least 4ms once they nest more than 5 deep (HTML spec), and Node turns a 0ms delay into 1ms. So in a browser an async diff takes at least 4ms per iteration, no matter how little work each iteration does.
diffWords on generated text in Chrome 154:
input
sync
async
500 words, 10% changed
9 ms
654 ms
2500 words, 10% changed
28 ms
2264 ms
2500 words, 30% changed
220 ms
7472 ms
Node 24 shows the same thing with a 1ms floor: 193 ms sync vs 2177 ms async on the last input.
That makes async mode impractical for its main job, which is keeping a page responsive while diffing a large document. It also uses up timeout, which counts the time spent waiting on timers.
Suggested fix: yield through a MessageChannel instead. Posted messages aren't clamped, and MessageChannel is both Baseline widely available and a global in current Node LTS, so it fits the compatibility policy. React's scheduler yields this way for the same reason. The same inputs with that change:
input
Chrome sync
Chrome async
Node async
500 words, 10% changed
4 ms
4 ms
24 ms
2500 words, 10% changed
26 ms
22 ms
31 ms
2500 words, 30% changed
224 ms
243 ms
219 ms
Chrome painted 15 frames during the slowest one, so the page stayed responsive. Each port has to be closed after its message, or it keeps a Node process alive.
I'd like to work on this, using the MessageChannel approach you suggested with a fallback where it isn't available. I'll include a test that shows async mode no longer waits on clamped timers.
Written with the help of an agent (Claude Code, claude-opus-5-5).
Activity
anzal1 commentedon Oct 10, 2026
I'd like to work on this, using the MessageChannel approach you suggested with a fallback where it isn't available. I'll include a test that shows async mode no longer waits on clamped timers.
Written with the help of an agent (Claude Code, claude-opus-5-5).
Yield with MessageChannel instead of setTimeout in async mode (kpdeck…