Atila
I'm on a mission to make code simple. When not recording screencasts or courses, you may find me either writing and talking about jamstack, performance, or developer tooling.
Lead Web Developer @ SAP
multithreading
paralellism
≠
single thread
multi threads
vs
concurrency
parallelism
vs
one at a time
from discord.com
simultaneous
from giphy.com
parallelism is
a special kind of
async
⏰ setTimeout
⏱ setInterval
🙏 promise
🪃 fetch
async
await
ℹ mdn.io/web-workers
Web-Worker tasks do not interfere with the UI
👋 bye bye, Blocking Scripts
🎯 Dedicated Worker
🤝 Shared Worker
Dedicated to one main script
Shared by multiple main scripts
🎯 Dedicated Worker
🤝 Shared Worker
🪟 Main Thread
`window`
`DedicatedWorkerGlobalScope`
`SharedWorkerGlobalScope`
`self`
SharedWorkers API removed from Webkit
📫 transferred, not cloned
👾 serialized objects
`worker.postMessage()`
🪐 different runtime
📡 sends error event
`worker.onerror = () => {}`
👮 only threadsafe DOM components
🔒 data restrictions (only serialized objects)
❌ own execution context
99%
of cases
add on
`worker.js`
request
origin is
`UID`
(universally unique identifier)
1%
of cases
🪐 different runtime
👾 serialized objects
👮 only threadsafe DOM components
🚫 no DOM manipulation
cool, now gimme some
self.addEventListener(
'message',
function (event) {
self.postMessage(runBigTask(event.data, 'vanilla-worker'))
},
false
)
export const Button = () => (
<button
onClick={async () => {
setData('loading')
const worker = new Worker(
new URL('../utils/vanilla-worker', import.meta.url),
{
name: 'vanilla-worker',
type: 'module',
}
)
worker.postMessage(TASK_SIZE)
worker.addEventListener('message', function (evt) {
setData(evt.data)
})
}}
>
Run Vanilla-WebWorker
</button>
)
better
please
Proxy API
RPC → `postMessage`
import { expose } from 'comlink'
import { runBigTask } from './big-task'
const worker = {
runBigTask: async (int: number) => (
await runBigTask(int, 'comlink-worker')
),
}
export type ComlinkWorker = typeof worker
expose(worker)
export const Button = () => (
<button
onClick={async () => {
setData('loading')
const worker = new Worker(
new URL('../utils/comlink-worker', import.meta.url),
{
name: 'runBigTaskWorker',
type: 'module',
}
)
const { runBigTask } = wrap<ComlinkWorker>(worker)
setData(await runBigTask(TASK_SIZE))
}}
>
Comlink WebWorker
</button>
)
🐝 subworkers
🧞♀️
🛰 and other types of workers
`importScripts()`
getting ⚡️out ⚡️ of the main-thread is doable and cheap
By Atila
JavaScript is not single-threaded anymore. And it has been a while. But we are still leaving all the processing in the same thread that we render things. Let's have a look on how we can do it better. Unblock the main thread forever!!!
I'm on a mission to make code simple. When not recording screencasts or courses, you may find me either writing and talking about jamstack, performance, or developer tooling.