When the Screen Never Catches Up: Understanding Rendering Starvation in JavaScript
Rendering starvation occurs when continuous or long-running JavaScript tasks prevent the browser from entering the rendering phase, blocking UI updates and causing the interface to appear frozen despite ongoing execution.
Thereâs a peculiar kind of slowness that doesnât come from broken logic.
The code runs.
State updates.
Events fire.
And yetâŚ
Nothing seems to change on the screen.
Clicks feel ignored.
Animations freeze.
Scrolling becomes heavy.
Itâs not that JavaScript stopped working.
Itâs that the browser never got the chance to render.
The Moment Between Frames
Rendering doesnât happen continuously.
It happens in moments.
Between tasks.
After JavaScript finishes its work, the browser gets a chance to:
- calculate layout
- paint pixels
- update the screen
This is the rendering phase.
And it only happens when the system has time.
When Time Never Comes
Rendering starvation happens when that moment never arrives.
Not because rendering is disabledâ
but because JavaScript never yields control.
The browser is always busy.
Always executing.
Never pausing.
A System That Never Breathes
Consider this:
while (true) {}Here, JavaScript never finishes.
So the browser never reaches rendering.
The screen freezes.
Not because rendering failedâ
but because it was never allowed to start.
A More Subtle Case
Starvation doesnât always look this obvious.
It can happen in smaller, repeated bursts.
function heavyTask() {
for (let i = 0; i < 1e8; i++) {}
}
setInterval(heavyTask, 0)Each task finishes.
But the next begins immediately.
There is no gap.
No space for rendering to occur.
And so the UI feels unresponsive.
The Illusion of Activity
What makes this confusing is that the system is not idle.
It is actively doing work.
Updating data.
Running logic.
But none of that work reaches the screen.
Because rendering is always waiting for its turn.
And that turn never comes.
Rendering Needs a Window
The browser doesnât interrupt JavaScript to render.
It waits.
It waits until:
- the current task finishes
- microtasks are processed
Only then does it attempt to paint.
If that moment is constantly delayedâ
rendering is starved.
A Frame That Never Forms
Modern interfaces aim for smooth updates.
Roughly 60 frames per second.
Each frame needs a slice of time.
But if JavaScript consumes that entire sliceâ
thereâs nothing left for rendering.
Frames are skipped.
And the experience breaks.
Not Just About Speed
Rendering starvation is not about slow code.
Itâs about uninterrupted code.
Even fast operations, repeated endlessly, can block the system.
Because what matters is not just how long tasks takeâ
but whether they allow pauses.
Letting the Browser Breathe
The solution is not to avoid work.
Itâs to structure it differently.
Break tasks into smaller pieces.
Schedule work in chunks.
Allow the event loop to continue.
Give the browser room to render.
Because rendering is not automatic.
It is opportunistic.
A Subtle Perspective
Rendering starvation reveals something deeper:
JavaScript doesnât control the screen directly.
It prepares changes.
But the browser decides when those changes become visible.
And if you never give it that opportunityâ
nothing appears.
A Final Thought
A responsive interface is not just about doing things quickly.
Itâs about doing them in a way that leaves space.
Space for frames.
Space for updates.
Space for the user to see whatâs happening.
Because sometimes, the difference between smooth and frozenâ
is not how much you do,
but whether you pause long enough for it to be seen.