Definitive guide to multi-threaded rendering on the Web
Use them multi core CPUs to speed up your web app.
During my Computer science graduate studies I took a ton of coursework dealing with threads, synchronization, race conditions, semaphores... aaand then ... I became a frontend engineer in 2013. The threads vanished, and I was left with the lonely main thread. Web workers were around, but not really.
But hey, its not 2013 any more!
Why do multi threaded rendering ?
The DOM is single threaded (still is, and might be forever). But we want to do more with it. Here are some cases where a single thread starts becoming a bottleneck:
Heavy data visualizations, dashboards with multiple visualizations
Apps with complex and sophisticated interaction patterns
Interactive infographics
Physics simulations
Low powered devices
What are my options?
Multi threading on the web can be classified into four broad categories:
Compute only
Prioritized scheduling
Parallelized create DOM
Parallelized create and mutate
Canvas
DOM
Lets take a closer look at each of these.
Compute Only
This is the traditional Web worker model. Compute on the client can be distributed to multiple Web Workers.
Implementations:
Web Workers and Friends (Shared worker, Service worker)
AudioWorklet: Run audio processing in a separate thread
React Worker DOM (Virtual DOM computes in a separate thread)
Prioritized scheduling
Work is rescheduled as per priority, giving a sense of a responsive application. Still uses a single thread.
Implementations:
Parallelized create DOM
Single compute thread (main thread)
The initial render load is shared by multiple workers.
PS: The worker is generally a server side process.
Implementations:
Facebook: Bigpipe
Ebay: Async Fragments
Parallelized create and Mutate (Canvas)
With the new Offscreen canvas API (widely available since March 2023), you can create and control a canvas from a Worker. This brings us within striking distance from our goal, true multi-threaded rendering.
Implementations:
Offscreen Canvas with transferControlToOffscreen.
Parallelized create and mutate (DOM)
The DOM is both created and mutated by separate workers. There are two approaches which make this possible, and we will talk about the current implementations for each.
Web Worker w/ DOM
Worker DOM library implemented DOM within web workers, all the mutations are done within the worker and then periodically synced with the Main DOM. Checkout these slides for more details on how this works under the hood.
Parallel DOM via cross origin SubFrames
With the release of performance isolation in Chrome 88, its now possible to have multiple subframes (iframes) on a webpage which might be running in a separate process. The PDoM library tries to exploit this capability by providing an ergonomic abstraction (async postMessage, multiple iframe management etc).
That’s all folks!
What we didn’t talk about today is you could also use the above techniques in combination with one another. For eg, you could use the “Compute only worker threads” with “Parallelized create only” to achieve performance benefits beyond just the initial render.
Disclaimer: The author is the author of PDom.