On this page · sections
JavaScript Rendering, Performance & Workers
Can you keep the main thread free for input — and know which work belongs in a Worker?
The main thread runs JS, style, layout, and much of paint. A long task is a frozen UI. Performance interviews are event-loop interviews with pixels attached.
These questions test:
- Critical rendering path
- Reflow vs repaint vs composite
- Long tasks and INP
requestAnimationFrame- Workers, structured clone, transferables
Questions
Rendering
Performance
Workers
Senior-Level Follow-ups
Rendering
1. The Rendering Pipeline
Why This Matters
“Make it faster” is not a plan. You need to know which stage you are hitting.
Problem
How does the browser go from HTML to pixels, and where does JS sit?
Example
HTML → DOM
CSS → CSSOM
DOM + CSSOM → render tree
Layout → geometry
Paint → pixels
Composite → layers to screenJS on the main thread can dirty style and layout. After a task and its microtasks, the browser may run rAF, then style/layout/paint.
Interview Answer
“The main thread interleaves JS with rendering. I describe DOM/CSSOM → render tree → layout → paint → composite. I optimize the stage I actually block — usually layout or a long JS task.”
2. Layout Thrashing
Why This Matters
Interleaving writes and reads forces the browser to flush layout repeatedly.
Problem
Why is this slow, and how do you batch it?
Example
el.style.width = "100px";
const h = el.offsetHeight; // forced layout
el.style.height = h * 2 + "px";Reads that force layout include offsetHeight, getBoundingClientRect, clientWidth.
Batch:
read all
then write all
(or write in rAF)Interview Answer
“A geometric read after a write flushes layout. I group reads, then writes. For visual updates I schedule
requestAnimationFrameso work lands in the same frame.”
Performance
3. Long Tasks and What to Measure
Why This Matters
A 200ms click handler is an INP problem even if Lighthouse LCP looks fine.
Problem
What is a long task, and which metrics would you quote?
Example
Tasks over ~50ms are “long.” They block input and paint.
Metrics:
| Metric | Asks |
|---|---|
| LCP | When the main content appears |
| INP | How late interactions are |
| CLS | Visual jumps |
| TBT | Main-thread blocking during load |
Tools: Performance panel, performance.mark, Event Timing, Long Animation Frames.
Fixes: split work, await between chunks, virtualize lists, move CPU to a Worker, reduce JS parse with code splitting.
Interview Answer
“I treat anything that occupies the main thread as user-visible. I measure INP for interaction, LCP for load, and the Performance profile for the actual function. I do not micro-optimize spreads while a 200ms reducer runs.”
Workers
4. Web Workers and postMessage
Why This Matters
Workers have a separate event loop and no DOM.
Problem
How do you move CPU work off the main thread?
Example
const worker = new Worker(new URL("./worker.js", import.meta.url), {
type: "module",
});
worker.postMessage({ type: "PARSE", payload: bigString });
worker.onmessage = (event) => {
use(event.data);
};self.onmessage = (event) => {
const ast = parse(event.data.payload);
self.postMessage({ type: "PARSED", ast });
};Messages are copied with structured clone. Functions, DOM nodes, and some objects cannot be cloned.
Interview Answer
“A Worker is another JS thread with its own loop and no DOM. I send data with
postMessage, handle clone limits, and keep the UI thread for input and rendering.”
Senior-Level Follow-ups
5. Composite-Only Properties
transform and opacity can often skip layout and paint, using compositor layers.
Animating top, left, width, or font-size typically costs layout.
Prefer transform for motion. Verify in the Performance panel — “can” is not “always.”
6. Structured Clone vs Transfer
Clone copies. Large ArrayBuffers should be transferred:
worker.postMessage({ buffer }, [buffer]);Ownership moves. The sender’s buffer is detached.
SharedArrayBuffer is shared memory and needs COOP/COEP headers. Most UI apps never need it.
7. When Not to Use a Worker
Do not Worker-ize tiny work: postMessage latency can exceed the task.
Do not put UI logic in a Worker — no DOM, no window.
Do not share mutable objects; you send copies (or transfers).
Good fits: parse, compress, image decode, crypto, search indexes.
Final Interview Strategy
1. Name the pipeline stage
2. Don't interleave layout reads and writes
3. Long tasks block INP
4. Measure before rewriting algorithms
5. Workers: no DOM, message passing
6. Transfer big buffers
7. Don't pay postMessage for 2ms of workSenior-level signal: Tie jank to a stage (JS, layout, paint) and a fix (yield, batch, Worker). Vague “use a Worker” without clone costs is not enough.