Skip to content

Instantly share code, notes, and snippets.

@Potherca
Last active April 8, 2025 15:12
Show Gist options
  • Save Potherca/6d08ac35617af9237427454954a2029d to your computer and use it in GitHub Desktop.
Save Potherca/6d08ac35617af9237427454954a2029d to your computer and use it in GitHub Desktop.

Local Web Worker

Under normal circumstances, a Web Worker should be passed a URL of the script to execute. However, a local function can also be used

This is done by converting a function to a string, converting that string to a Blob, and converting that Blob to an Object URL.

Code

The code to do this would look a bit like this:

/* Some code we want to use as Worker */
const workerCode = () => {
  onmessage = event => {
    postMessage('some message')
  }
}

/* Create a Worker from the function */
const code = workerCode
  .toString()   // Convert the function to a string (Duh)
  .slice(10,-3) // This removes the "() => {" and closing "\n}\n"
const blob = new Blob([code], {type: 'application/javascript'})
const worker = new Worker(URL.createObjectURL(blob))

/* Send a message to the Worker code */
worker.postMessage('Hello Worker!')

/* Receive a message from the Worker code */
worker.onmessage = function(event) {
  event.data // The message received from the worker
}

Be aware that the workerCode does not share the scope with its parent! As it is a separate script, it also has no window, document, etc.

Example

To view a live example, visit: https://gist.pother.ca/6d08ac35617af9237427454954a2029d/

<!doctype html>
<html color-mode="user" lang="en">
<meta charset="utf-8" />
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
<link href="https://fonts.googleapis.com/" rel="dns-prefetch" />
<link crossorigin href="https://cdn.jsdelivr.net/" rel="preconnect" />
<link href="https://favicon.potherca.workers.dev/64" rel="icon shortcut" type="image/svg+xml" />
<link href="https://cdn.jsdelivr.net/npm/[email protected]/mvp.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/gh/Potherca/CssBase@main/css/created-by-potherca.css" rel="stylesheet" />
<style>
/* Generic tweaks to MVP.css styles */
::selection {
background-color: var(--color-link);
text-shadow: 0 0 3px white;
}
body, html {
min-height: 100vh;
}
footer {
align-items: center;
background-color: var(--color-bg-secondary);
display: flex;
flex-wrap: wrap;
justify-content: space-around;
padding: 0.35rem 1rem 1rem 0;
position: sticky;
top: 100%;
}
footer p {
width: fit-content;
text-align: center;
}
footer svg {
height: 2rem;
}
header {
padding-bottom: 0;
}
nav {
margin-bottom: 0;
}
title {
display: block;
}
/* Page specific styles */
</style>
<header>
<nav>
<h1>Local Web Worker</h1>
</nav>
</header>
<main>
<section>
<p>
Under normal circumstances, a Web Worker should be passed a URL of the script to execute.
However, a local function can also be used
</p>
<p>
This is done by converting a function to a string, converting that string to a Blob, and converting that Blob to an Object URL.
</p>
<h2>Code</h2>
<p>The code to do this would look a bit like this:</p>
<pre><code>
/* Some code we want to use as Worker */
const workerCode = () => {
onmessage = event => {
postMessage('some message')
}
}
/* Create a Worker from the function */
const code = workerCode
.toString() // Convert the function to a string (Duh)
.slice(10,-3) // This removes the "() => {" and closing "\n}\n"
const blob = new Blob([code], {type: 'application/javascript'})
const worker = new Worker(URL.createObjectURL(blob))
/* Send a message to the Worker code */
worker.postMessage('Hello Worker!')
/* Receive a message from the Worker code */
worker.onmessage = function(event) {
event.data // The message received from the worker
}
</code></pre>
<p>
Be aware that the <code>workerCode</code> <strong>does not</strong> share the scope with its parent! <br>
As it is a separate script, it also has no <code>window</code>, <code>document</code>, etc.
</p>
</section>
<section>
<form>
<fieldset>
<legend><h2>Example</h2></legend>
<button>Send Message</button>
</fieldset>
</form>
</section>
<section>
<output>
<ul></ul>
</output>
</section>
</main>
<footer>
<p>
<small>sponsored by</small><br>
<a href="https://muze.nl/">
<svg data-name="Logo Muze" viewBox="0 0 245 50" xmlns="http://www.w3.org/2000/svg">
<path d="M13 49a8 8 0 0 1-5-2c-2-1-2-3-2-6v-8a9 9 0 0 0-1-5 4 4 0 0 0-3-2v-2q4-1 4-6V9q0-4 2-6a8 8 0 0 1 5-2v3a4 4 0 0 0-3 1 8 8 0 0 0-1 5v8q0 6-4 7 4 1 4 8v7a15 15 0 0 0 0 3 5 5 0 0 0 1 2 3 3 0 0 0 1 1 5 5 0 0 0 2 0Z" fill="#1a1a1a" stroke="#1a1a1a" stroke-miterlimit="10" />
<path d="M89 49h-7V20a15 15 0 0 0-3-9 10 10 0 0 0-8-4 13 13 0 0 0-9 3 11 11 0 0 0-4 9v30h-7V19a11 11 0 0 0-3-9 13 13 0 0 0-9-3 10 10 0 0 0-9 4 14 14 0 0 0-3 9v29h-6V21c0-6 1-11 5-14a18 18 0 0 1 12-6c7 0 13 3 17 9 4-6 9-9 16-9a19 19 0 0 1 13 6c3 3 5 8 5 14Z" fill="#1a1a1a" />
<path d="M137 28a21 21 0 0 1-6 15 20 20 0 0 1-15 6 20 20 0 0 1-15-6 21 21 0 0 1-6-15V1h7v28a14 14 0 0 0 4 10 14 14 0 0 0 10 4 14 14 0 0 0 10-4 14 14 0 0 0 5-10V1h6Z" fill="#c2000b" />
<path d="M178 49h-35v-6l25-36h-24V1h32v6l-25 36h27Zm49-16a23 23 0 0 1-9 12 24 24 0 0 1-13 4 23 23 0 0 1-17-7 23 23 0 0 1-8-16 23 23 0 0 1 8-18 23 23 0 0 1 18-7 24 24 0 0 1 16 8q6 6 6 15v3h-41a17 17 0 0 0 6 12 18 18 0 0 0 12 4c7 0 12-3 15-10Zm-5-11a18 18 0 0 0-29-11 17 17 0 0 0-6 11Z" fill="#1a1a1a" />
<path d="M232 46a5 5 0 0 0 2 0 3 3 0 0 0 1-1 5 5 0 0 0 1-2 15 15 0 0 0 0-3v-7q0-7 4-8-4-1-4-7v-8a8 8 0 0 0-1-5 4 4 0 0 0-3-1V1a8 8 0 0 1 5 2q2 2 2 6v9q0 5 4 6v2a4 4 0 0 0-3 2 8 8 0 0 0-1 5v8c0 3 0 5-2 6a8 8 0 0 1-5 2Z" fill="#1a1a1a" stroke="#1a1a1a" stroke-miterlimit="10" />
</svg>
</a>
</p>
<p class="created-by">
The Source Code for this project is available
<a href="https://gist.github.com/6d08ac35617af9237427454954a2029d/">as a Gist</a>
under a <a href="https://mozilla.org/MPL/2.0/" rel="license"> Mozilla Public License 2.0 (MPL-2.0)</a>
&ndash; Created by
<a class="potherca" href="https://pother.ca/">Potherca</a>
</p>
</footer>
<script>
const workerCode = () => {
/* Please be aware that all code here DOES NOT share the scope with its parent! */
onmessage = function(event) {
const message = '[Worker] Message received:' + JSON.stringify(event.data)
postMessage(message)
}
}
console.log = message => {
document.querySelector('output ul').insertAdjacentHTML('beforeend', `<li>${message}</li>`)
}
const code = workerCode.toString().slice(10,-3);
const blob = new Blob([code], {type: 'application/javascript'})
const worker = new Worker(URL.createObjectURL(blob))
document.querySelector('form').addEventListener('submit', event => {
event.preventDefault()
const message = 'Hello Worker!'
console.log(`Sending message to worker: <code>${message}</code>`)
worker.postMessage(message)
})
worker.onmessage = function(event) {
console.log(`Received message from worker: <code>${JSON.stringify(event.data)}</code>`)
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment