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 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 mentions three types of workers:
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.
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
- Implementing a custom webpack configuration
- 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
Create a
.js
file in yourpublic
folder;Implement an
onmessage
function that receives anevent
as a parameter, process data* and, at the end of its execution, callspostMessage
, passing the results as a parameter.
*The data passed as a parameter to this worker can be retrieved from event.data
property.
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.Implement the functions
onmessage
andonerror
.
They are callbacks executed when the messages are received from the Worker and in case of any error, respectively.Considering the problem you need to solve, create chunks from your data (you may use
lodash/fp/chunk
function) and iterate on them callingworker.postMessage
passing the chunk as parameter.
The structure of both files will be similar to these:
// ./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)
}
// 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 by all browsers.*
You can find a full example of this implementation in this repo.
Hope you liked it! Share and comment.
Cover image by @helloimnik
Top comments (1)
Hey, needed some help with shared web workers. ping me?