Skip to content

Instantly share code, notes, and snippets.

@Potherca
Last active May 11, 2023 13:42
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • 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

This codepen demonstrates how a Web Worker can be used without a remote URL: https://codepen.io/potherca/full/OJxbmMj

<h1>Local Web Worker</h1>
<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.
<h2>Example</h2>
<button>Send Message</button>
<ul>
</ul>
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)
}
}
const log = message => {
document.querySelector('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('button').addEventListener('click', () => {
const message = 'Hello Worker!'
log(`Sending message to worker: <code>${message}</code>`)
worker.postMessage(message)
})
worker.onmessage = function(event) {
log(`Received message from worker: <code>${JSON.stringify(event.data)}</code>`)
}
@import "https://cdnjs.cloudflare.com/ajax/libs/milligram/1.4.1/milligram.css"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment