VueJS - Dedicated Web Worker Implementation
Tags: vue, javascript, webworker, beginners
Published: 2021-05-06 22:16:55

JavaScript is a synchronous and single-threaded language and, because of it, it cannot take full advantage of multi-core CPUs.

Nevertheless, it provides some mechanisms that allow us to perform certain asynchronous operations and wait for their responses without blocking the main thread and, sometimes, the interface.

[This article](https://www.freecodecamp.org/news/javascript-from-callbacks-to-async-await-1cc090ddad99/) explains each one of these mechanisms.

Even though there are some ways to perform asynchronous operations in JavaScript, sometimes, they are not enough. Consider, for example, a big `for` loop where operations need to be performed following a certain order.

There is not a way for us to do that asynchronously or even taking advantage of the multiple cores of our CPU. Well, at least, there wasn't.

With HTML 5 and modern web APIs, we are now capable of executing code that demands heavy processing without blocking the main thread and, consequently, the interface.
Today, I am talking about one of them: the Web Workers.

The [official specification](http://www.whatwg.org/specs/web-workers/current-work/) mentions three types of workers:

- <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers" target="_blank">Dedicated Workers</a>
- <a href="https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker" target="_blank">Shared Workers</a>
- <a href="https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker_API" target="_blank">Service Workers</a>

**Dedicated Workers** are instantiated by the main process and can communicate only with it.

**Shared Workers** may be accessed by all processes executed in the same origin (different browser tabs, iframes or other shared workers)

**Service Workers** are event-oriented workers registered to an origin and a path. They are capable of controlling the website/page to which they are related, intercept and modify navigation and resource requests, and cache resources in a very granular way.

<figure>
<img src="https://thecodersblog.com/assets/images/working-of-web-worker.png" />
<figcaption>Source: <a href="https://thecodersblog.com/web-worker-and-implementation" target="_blank">https://thecodersblog.com/web-worker-and-implementation</a></figcaption> 
</figure>

---

In this post, I am going to talk about how to implement a **Dedicated Worker** in VueJS and use it to take advantage of multi-core CPUs.

There are some ways to implement Web Workers within a VueJS project:

- Using a plugin like *[vue-worker](https://github.com/israelss/vue-worker)*
- Implementing a [custom webpack configuration](https://github.com/webpack-contrib/worker-loader)
- Instantiating a Worker referencing a simple JS file (let's talk about this one 😆)

It is pretty easy to implement a Dedicated Web Worker in a VueJS project.

### Implementing a Dedicated Web Worker in VueJS

1. Create a `.js` file in your `public` folder;

2. Implement an `onmessage` function that receives an `event` as a parameter, process data* and, at the end of its execution, calls `postMessage`, passing the results as a parameter.

_*The data passed as a parameter to this worker can be retrieved from `event.data` property._

3. In a Vue Component, instantiate a new Worker and pass the absolute path of the recently created `.js` file as a parameter in its constructor.

4. Implement the functions `onmessage` and `onerror`. 
They are callbacks executed when the messages are received from the Worker and in case of any error, respectively.

5. Considering the problem you need to solve, create chunks from your data (you may use `lodash/fp/chunk` function) and iterate on them calling `worker.postMessage` passing the chunk as parameter.

The structure of both files will be similar to these:

```javascript
// ./public/worker.js file

onmessage = function(event) {
  var data = event.data // data sent by the Vue component
is retrieved from 'data' attribute

  var result = doSomething()

  postMessage(result)
}

```


```javascript
// Worker.vue
import { chunk, map } from 'lodash/fp'

export default {
  props: ['data'],
  computed: {
    chunkedData() {
       const size = Math.ceil(this.data.length / 4) // In this case, 4 threads will be created
       return chunk(size, this.data)
    }
  },
  run() {
    const worker = new Worker('/worker.js')
   
    worker.onmessage = function(event) {
      const data = event.data // Data passed as parameter by the worker is retrieved from 'data' attribute
      console.log(data)
    }

  worker.onerror = console.error // This will be executed in case of any errors

   map(chunk => worker.postMessage(chunk), this.chunkedData)
  }
}
```

Using this structure you will be able to instantiate a Web Worker, split the data into chunks and process each one of them asynchronously taking advantage of multiple threads and avoiding interface and browser freezing.

***Obs.: I strongly suggest using ES5 code inside the `worker.js` file. By the time this article is being written, ES6+ code within Web Workers is still [not fully supported](https://stackoverflow.com/a/45578811/3337564) by all browsers.**

You can find a full example of this implementation in [this repo](https://github.com/vcpablo/vuejs-web-worker).

Hope you liked it! Share and comment.

*Cover image by [@helloimnik](https://unsplash.com/@helloimnik)*