Explain Codes LogoExplain Codes Logo

Web workers without a separate Javascript file?

javascript
web-workers
javascript-optimization
async-programming
Anton ShumikhinbyAnton Shumikhin·Dec 27, 2024
TLDR
const code = `onmessage = e => postMessage(e.data);`; const blob = new Blob([code], { type: 'text/javascript' }); const worker = new Worker(URL.createObjectURL(blob)); worker.postMessage('Hello'); worker.onmessage = e => console.log(`Worker says: ${e.data}`);

The above snippet chalks out the bare bones method to create a Web Worker inline with the help of a Blob. The worker simply replies with any message passed into it.

Mechanism behind the magic of inline worker

Using Blob objects alongside dynamic URL creation, we can strategically encapsulate worker operations within our main body of JavaScript. This leads to more streamlined and manageable code.

Recipe for constructing inline workers

The art of web worker origami begins with transforming a function into a string and creating a worker from a Blob. This keeps your application self-contained and neat as a pin:

const workerFunction = function() { // Worker code goes here... }; const code = workerFunction.toString(); const blob = new Blob([`(${code})()`], { type: 'text/javascript' }); const worker = new Worker(URL.createObjectURL(blob));

Remember to clean up after your party! Revoke the dynamically created object URL for a tidy resource cleanup:

URL.revokeObjectURL(worker.url);

Taking worker handling to next level

  • For those who dream of multiple tab scenarios or require offline functionality, consider ServiceWorker and SharedWorker as alternative options.
  • To boost performance, consider caching the worker code using CacheStorage. Loading less data leads to quick start-up times between sessions.
  • Closure Compiler can become your best friend if your application needs to digest minified scripts. It can squeeze inline worker and main scripts together.

Libraries & utilities to turbocharge your code

When you have a hammer, everything looks like a nail. Well, here are some hammers:

  • Workerize: Moves any module export to a worker. Ideal for those tough nails (heavy tasks).
  • Greenlet: Transforms async functions to workers. Perfect for light carpentry (light tasks).
  • For those love handwritten letters, check out bridged-worker.js gist or the complete GitHub repository for some nice patterns for cross-thread communication.

Context matters

A worker script running under shared context needs an awareness of its execution environment. Because nobody likes to speak out of context:

if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) { // Working like a beast } else { // Vacation time }

Toolbox: Select the right tool for your need

Compare & contrast: Workerize vs. Greenlet

  • Workerize: For the big jobs. Bundles entire modules as web workers.
  • Greenlet: For the delicate tasks. Changes async functions into workers.

Building bridges: Bridged workers

  • Bridged workers enable more orderly, maintainable code by segregating the worker logic into comprehensible units.
  • Parent-to-worker and worker-to-parent messaging using bridged workers is more methodical and encapsulated, which translates to better debugging and testing.

Going against the flow: Synchronous to asynchronous

By morphing synchronous code into asynchronous using inline workers, you can improve UI responsiveness and essentially take care of background processing. The fruits of your labor will be interactive and engaging web applications.

Brewing a perfect workers brew: Pro-tips & caveats

Remember to clean up

  • Like any good New Year's party, there are leftover pizza slices and beer cans to clean up. Same goes for inline workers. Consider memory usage and cleanup; inline workers still crave for a proper garbage collection.
  • The magic_cleaner.js is URL.revokeObjectURL(). Use it after the worker's termination to clean up extra mess.

Does your browser play nice?

  • Not every browser plays nice with the Worker object. Perform feature detection and have polyfills or fallbacks as a contingency plan.
  • Validate blob creation compatibility, especially when dealing with older browsers who still live in the past.

Knowing when to keep it simple and when to go all out

  • Keep code readable and separated during development.
  • Use build tools to combine and minify your code for production, ensuring optimal performance and load time. Because speed matters!