Public Domain, https://commons.wikimedia.org/w/index.php?curid=3976299
Smooth animation means painting 60 frames per second
Browser takes ~4-6 ms per frame to do work
All of our JS for each frame has to take ~10-12 ms or less
JavaScript
Style
Layout
Paint
Composite
https://developers.google.com/web/fundamentals/performance/rendering
16 ms
JavaScript
Style
Layout
Paint
Composite
Browser can skip steps if nothing changes
16 ms
JavaScript
Style
Layout
Paint
Composite
16 ms
UI/Local Logic
JavaScript
Style
Layout
Paint
Composite
16 ms
CSS-in-JS Runtime
UI/Local Logic
JavaScript
Style
Layout
Paint
Composite
16 ms
CSS-in-JS Runtime
UI/Local Logic
Front-end Framework
JavaScript
Style
Layout
Paint
Composite
16 ms
CSS-in-JS Runtime
UI/Local Logic
Front-end Framework
State Management Logic
We've exceeded our frame budget and introduced jank
JavaScript
Style
Layout
Paint
Composite
16 ms
The more blocking JavaScript that we have, the more frames that we will drop
while (true) {
console.log('To infinity and beyond!');
}
// Will never run!
extremelyImportantFunction();
This is why fetch or setTimeout don't block the render
Jake Archibald - "In the Loop"
The Event Loop offers a framework for concurrency, and Promises/Tasks offer a good way of handling it in our code
To enable parallelism, we need to offload work from our main UI thread using Web Workers
Run scripts in separate background thread, so that we don't block the main thread
When to use Web Workers:
// worker.js
function handleMessage(e) {
if (e.data === 'ping...') {
self.postMessage('pong!');
}
}
self.addEventListener('message', handleMessage);
// main.js
const worker = new Worker('worker.js');
function handleMessage(e) {
console.log(e.data);
}
worker.addEventListener('message', handleMessage);
worker.postMessage('ping...');
// Console: pong!
Webpack
worker-loader: github.com/NativeScript/worker-loader
worker-plugin: github.com/GoogleChromeLabs/worker-plugin
Rollup
rollup-plugin-off-main-thread: github.com/surma/rollup-plugin-off-main-thread
Parcel
(Web Worker support is baked in! Hooray!)
Depending on the nature of the code, you may not need to alter build system (i.e. using URL.createObjectURL and Blob)
Examples:
workerize: github.com/developit/workerize
comlink: github.com/GoogleChromeLabs/comlink
The Actor model: www.brianstorti.com/the-actor-model/
Treat different components of your UI system as "actors":
Example
Mehdi Vasigh - "Getting Started with JavaScript Web Workers and Off-Main-Thread Tasks"
dev.to/mvasigh/getting-started-with-javascript-web-workers-and-off-main-thread-tasks-4029
Surma - "Use web workers to run JavaScript off the browser's main thread"
Surma - "The main thread is overworked and underpaid"
www.youtube.com/watch?v=7Rrv9qFMWNM
Jason Teplitz - "Using Web Workers for more responsive apps"
Questions? Ask me here or on Twitter!