12/08/2018, 16:54

Simple Web Workers workflow with webpack

What is Web Worker? Web Worker is a simple way to separate scripts execution into background threads for web applications. A spawned worker can perform tasks and interact with main thread via messages API. This is the basic diagram of Web Worker API. You can read more in following articles: ...

What is Web Worker?

Web Worker is a simple way to separate scripts execution into background threads for web applications. A spawned worker can perform tasks and interact with main thread via messages API.

This is the basic diagram of Web Worker API. You can read more in following articles:

  • An Introduction to Web Workers JavaScript API - Hongkiat
  • Giới thiệu API Web Worker trong JavaScript - Viblo
  • Cơ bản về Web Workers - Viblo

However, in most cases web apps require quite simple usage of web workers to fetch some big data or process a single expensive operation. This makes their usage quite complicated.

In this article I am going to describe how to use web workers in much more simple way.

Worker-loader

While webpack allows modules to be built with webworker target, in most cases it is excessive and not convenient as it requires additional configurations to be done.

More simple way is to use special worker-loader.

First install the loader plugin.

npm i -D worker-loader

Now, create your worker file.

// sample.worker.js
self.addEventListener('message', (event) => {
  if (event.data === 'ping') {
    self.postMessage('pong')
  }
})

The simplest way is to use inline loader query in your main script

// index.js
import Worker from 'worker-loader!./sample.worker';

let w = new Worker();
w.postMessage('ping');
w.onmessage = (event) => {
  console.log(event.data);
};

If you don’t want to use inline query, you can always define a rule in your webpack config

// webpack.config.js
{
  test: /.worker.js$/,
  use: [
    { loader: 'worker-loader' },
  ],
}

Now you can import the file directly and receive a worker constructor.

Promise workers

What if you need to separate a simple promise into its own thread? Writing a dedicated worker would produce excess code in most cases.

For such purpose we can use promise-worker package.

npm i promise-worker

It consists of two main components.

First allows to register a worker from a function. You should use it in your worker files.

Note that functions returning promises (or async functions) are supported as well

// sample.worker.js
import registerPromiseWorker from 'promise-worker/register';

registerPromiseWorker((message) => {
  return 'pong';
})

// OR

registerPromiseWorker(async (message) => {
  return 'pong';
})

Second allows to use created worker as a promise. You should use it in your main script.

// index.js

import PromiseWorker from 'promise-worker'
import worker from './sample.worker'

const promiseWorker = new PromiseWorker(worker());

(async () => {
  try {
    let response = await promiseWorker.postMessage('ping')
    console.log(response)
  } catch (e) {
    // handle error
  }
})();

// OR

promiseWorker.postMessage('ping').then(function (response) {
  console.log(response)
}).catch(function (error) {
  // handle error
});

Now you can execute the promise whenever you need it in your code.

Workerize / Workerize loader

Although the package looks very promising, I experienced several bugs and couldn’t make it run properly. When the article was written, it was on version 0.1.6. I hope developers will fix all issues soon

0