Web Workers
Beyond The Wall
In particular, never use the main thread to perform long-running or potentially unbounded tasks, such as tasks that require network access. Instead, always move those tasks onto background threads.
—Apple Developer Guide
Because of the single thread model described above, it's vital to the responsiveness of your application's UI that you do not block the UI thread.
—Android Developer Guide
In the Web Platform, the Main thread is also the UI thread.
w.addEventListener('message', handler)
function handler(e) { /*e.data*/ }
DedicatedWorkerGlobalScope
addEventListener('message')
importScripts()
<script></script>
<script></script>
<script></script>
importScripts()
<script></script>
<script></script>
<script></script>
importScripts()
<script></script>
<script></script>
<script></script>
importScripts()
<script></script>
<script></script>
<script></script>
postMessage
Not quite the same as window.postMessage
Serialization
postMessage(JSON.stringify(obj));
- String
- Number
- Object
- Array
- Boolean
- null
Structured Clone Algorithm
- String
- Number
- Object
- Array
- Boolean
- null
- String
- Number
- Object
- Array
- Boolean
- null
- Date
- RegExp
- Circular References
- Blob
- File
- ImageData
// fibworker.js
addEventListener('message', function (e) {
var n = e.data;
var a = 0, b = 1, f = 1;
for(var i = 2; i <= n; i++) {
f = a + b;
a = b;
b = f;
}
postMessage(f);
});
// app.js
var fibonacciWorker = new Worker('fibworker.js');
fibonacciWorker.addEventListener('message', function (e) {
console.log(e.data); // result
});
fibonacciWorker.postMessage(20); // request
// interviewWorker.js
addEventListener('message', function (e) {
var message = e.data;
if (message.method === 'fibonacci') {
postMessage(fibonacci(message.input));
}
if (message.method === 'fizzbuzz') {
postMessage(fizzbuzz(message.input));
}
});
function fibonacci (n) {
/* No Spoilers!! */
}
function fizzbuzz (n) {
/* No Spoilers!! */
}
var w = new Worker('interviewWorker.js');
if (question === 'fizzbuzz') {
w.postMessage({ method: 'fizzbuzz', input: input });
}
if (question === 'fibonacci') {
w.postMessage({ method: 'fibonacci', input: input });
}
// app.js
var remoteFibonacci = (function () {
var worker = new Worker('fibworker.js');
var callId = 0;
return function remoteFibonacci (n) {
var cId = callId;
return new Promise(function (resolve, reject) {
w.postMessage({
input: n,
callId: cId
});
w.addEventListener('message', function (e) {
if (e.data.callId === cId) {
resolve(e.data);
}
});
});
callId++
};
})();
// fibworker.js
addEventListener('message', function (e) {
var message = e.data;
var callId = message.callId;
var n = message.input;
var a = 0, b = 1, f = 1;
for(var i = 2; i <= n; i++) {
f = a + b;
a = b;
b = f;
}
postMessage({
callId: callId,
result: f
});
});
remoteFibonacci(20).then(alert);
// fibworker.js
addEventListener('message', function (e) {
var message = e.data;
var callId = message.callId;
var n = message.input;
var a = 0, b = 1, f = 1;
for(var i = 2; i <= n; i++) {
f = a + b;
a = b;
b = f;
}
setTimeout(function () {
postMessage({
callId: callId,
result: f
});
}, Math.random() * 10000);
});
PromiseRPCWorkerFactoryBean
// fibworker.js
importScripts('promiseWorker.js');
function fibonacci (n) {
var a = 0, b = 1, f = 1;
for (var i = 2; i <= n; i++) {
f = a + b;
a = b;
b = f;
}
return f;
}
// register comes from promiseWorker.js
register({
fibonacci: fibonacci
});
promiseWorker('fibworker.js').then(function (api) {
api.fibonacci(20).then(alert);
});
function businessLogic() {
var n = getFoo();
n = frobulate(n);
var result = fibonacci(n);
showPopupWindow();
return result;
}
function businessLogic(callback) {
var n = getFoo();
frobulate(n)
.then(fibonacci)
.then(function (result) {
showPopupWindow();
callback(result);
});
}
function businessLogic() {
var n = getFoo();
n = frobulate(n);
var result = fibonacci(n);
showPopupWindow();
return result;
}
async function businessLogic() {
var n = getFoo();
n = await frobulate(n);
var result = await fibonacci(n);
showPopupWindow();
return result;
}
import {magic} from "future.js";
Any non-UI operation that can be done in a separate thread, should.
Must be separate file
More HTTP requests = :(
function BlobWorker(fn) {
var code = fn.toSource();
var blob = new Blob(
[code],
{"type": "text/javascript"}
);
var url = URL.createObjectURL(blob);
return new Worker(url);
}
DO NOT DO THIS
UNLESS YOU WANT TO THEN OKAY
DO NOT DO THIS
UNLESS YOU WANT TO THEN OKAY
Service Workers!
Start the multithreading today!
Thanks!
@potch · github.com/potch