/Freelancer

:necktie: An implementation of on-the-fly defined WebWorkers that are created inline using data URIs, rather than separate physical files — for the benefit of all humanity.

Primary LanguageJavaScriptGNU General Public License v3.0GPL-3.0

Freelancer

npm i freelancer --save

An implementation of on-the-fly defined WebWorkers that are created inline using data URIs, rather than separate physical files — for the benefit of all humanity.

example: heroku   •   ~500 bytes gzipped.

Travis   npm   License MIT

Getting Started

Freelancer uses the same interface as Worker except the passed parameters upon instantiation are slightly different.

Normally when invoking new Worker you pass the location of the file, whereas with new Freelancer you pass a function that contains the body of the worker.

Freelancer also allows an optional second parameter to be passed that allows you to send additional options to the worker.

import { Freelancer } from 'freelancer';

const worker = new Freelancer(() => {
   
    self.addEventListener('message', event => {
        console.log(event.data);
        self.postMessage('Pong!');
    });
    
});

worker.addEventListener('message', event => console.log(event.data));
worker.postMessage('Ping?');

It's worth bearing in mind that the worker is still a separate thread and thus the typical rules of closures no longer apply – any parameters you would like to be received by the worker would need to be sent using postMessage or by passing parameters upon instantiation.

Passing Parameters

Upon instantiation of Freelancer you can use the second parameter to pass options that will be pushed to the worker – passed options will be serialized using JSON.stringify and thus any data sent needs to be serializable – which essentially means you're unable to pass by reference, and circular references will cause issues.

import { SharedFreelancer } from 'freelancer';

const options = { send: 'Ping?', respond: 'Pong!' };

const worker = new SharedFreelancer(options => {
   
    self.addEventListener('message', event => {
        console.log(event.data);
        self.postMessage(options.respond);
    });
    
}, options);

worker.addEventListener('message', event => console.log(event.data));
worker.postMessage(options.send);

Although we refer to it as the second parameter you are in fact able to pass an infinite amount of parameters to the worker – the only requirement is that the first parameter is the worker's function.

Dynamic Imports

When defining a worker inline you'll lose the ability to import because the declaration needs to be at the top-level – instead you should prefer dynamic imports using async functions or a simple Promise.then.

import { Freelancer } from 'freelancer';
import translate from './translator';

const worker = new Freelancer(async () => {
   
    const translate = await import('./translator');
    
    self.addEventListener('message', event => {
        self.postMessage(translate(options.respond));
    });
    
});

worker.postMessage(translate(options.send));

Unsupported Worker

In some cases SharedWorker — or to a lesser extent Worker — may be undefined due to a lack of browser support (see issue). When a worker is unsupported you'll receive an error message, and thus it's crucial to determine browser support before using a particular worker.

forthebadge