04 Aug 2016
The thread that runs the web worker code has some environment limitations, which includes no access to the DOM or global objects such as window.  contains a list of functions and methods available to a Web Worker.
Besides that, memory is not shared between the threads, having to be explicitly serialized (so it can be cloned) and passed via a method (
postMessage()). This can lead to performance issues if the amount of data to be copied is large. In Transferable Objects we’ll discuss an alternative.
Workers might spawn their own workers.
Let’s work a simple example. Imagine we have two files, main.js and worker.js (in the same directory):
By default data is copied when sending information back and forth between the main thread and the worker, using a process called structural cloning.
The serialization/deserialization can be expensive, for which case there is an alternative: transferrable objects. More specifically, we can work with ArrayBuffers, which can be “transferred” instead of cloned, which is a more performant operation, more precisely, O(1).
We’ll first cover
ArrayBuffers and then see how to apply it in a context of Web Workers.
According to :
ArrayBufferis a data type that is used to represent a generic, fixed-length binary data buffer. You can’t directly manipulate the contents of an ArrayBuffer; instead, you create a typed array view or a DataView which represents the buffer in a specific format, and use that to read and write the contents of the buffer.
ArrayBuffer basically represents an unstructured array of bits, which, to have any meaning/interpretation, needs a view, which can be an array of 32-bit unsigned ints or 16-bit unsigned ints. In the example below we create an array buffer of 100 bytes.
This is a very interesting model. In
ArrayBuffers one explicitly work with the serialized form of the data and create views on top of them. I’m used to work with the views-first, that is, create a class representing some data and eventually add serialization/deserialization methods. One advantage of working with serialized data is that we don’t need to write the serialization methods, only the deserialization. The major disadvantage is that you need to know upfront how much memory you’ll have to use.
We can extend the example above to be used between a worker and the main thread.
and in the
By logging the output to the console, we can see the main thread received the values written to the array buffer by the worker and after the worker transferred the buffer data, it was emptied out.
Note in the
postMessage() API, we provide buffer as a the first parameter and then it also appears in the list indicating it should be transferred, not copied. Having to pass it twice is a bit confusing in my opinion, but this is to allow the example below, in which the objects transferred are nested inside another structure (in this case an object) and we want to transfer both
buffer2 but not the top-level object. I’m not sure which use case the API designers had in mind, though.
If any errors are uncaught by the worker, it can be caught from the main thread through the onerror callback:
Where e is an instance of ErrorEvent. We can simulate an error on the worker.js code:
The main thread can terminate the worker
or the worker can terminate itself:
A lot of the examples using Web Workers involve doing some fake expensive calculation in the worker thread, but I haven’t found any real-world application.
StackOverflow offers some ideas, including one that is dimissed as bad uses of Web Workers (polling) or from projects that are long defunct (Mozilla Skywriter). The main issue is that most of time heavy processing is done on the server.
One idea that came to mind is to use web-workers in React. React defers a lot of DOM work to the end by working with the concept of a virtual DOM. Web-workers don’t have access to the DOM but they do have it for virtual DOMs. Turns out this idea has been explored already [7, 8] but there were some technical difficulties in implementing events.
In this post we studied Web Workers and some examples utilizing it. I learned a few other related topics like ArrayBuffers, and Compositor Workers. I was a bit disappointed with the lack of compelling applications using Web Workers. I’ll try it out in some of my projects and see if I can any benefits from it.
Some of the code presented in this post is available on Github.