Recently, while working with a large and complex data grid, we discovered that we had an algorithm that took five whole seconds to complete. (That doesn't sound long, but user attention spans are notoriously short.) First, we tried to delay that calculation so it did not start until the rest of the page had loaded. But even then, we found that while the task executed, it completely froze up the UI, leaving the user unable to scroll, click, or do anything but beachball and wait.
Luckily, we live in an HTML5 world where browsers have opened the door to the asynchronous world of web workers. (Note that this article covers workers in general, and will not address service workers, a specific subtype of web worker that’s quite popular.)
Introducing web workers
Web workers operate on their own thread. They are able to make network requests, and you can load in external dependencies as needed (for example, in the data grid project, we needed lodash for some utility functions). They do not have access to the DOM or certain other resources from the main context. However, using message events, it is easy to send relevant information from the page to the worker and back (after the operation has been completed).
The worker thread (left) is busy; the main threat (right) is free
A major benefit of web workers is freeing up the main thread to do other things while you run your processor-intensive calculations. Especially when using a virtual-DOM based framework, it’s great to have the main thread available to manipulate and load the user interface.
Web workers, when used appropriately, can definitely improve the perceived performance of a page. There are a few considerations though. Namely, the transfer of data in both directions will take some amount of time in itself (though benchmarking has shown that these events take milliseconds). If it’s still taking too long, there are strategies to optimize workers for speed and performance.
As for the data grid? We were able to successfully leverage a web worker to perform our calculation in its own thread, freeing up the UI and shaving almost 2000 ms off our total processing time.
Want to explore web workers further? I’ve created a simple example repository. Since we at Eikos are big into Vue, we’ve used a webpack plugin called workerize-loader to simplify communication between our Vuex store and our worker thread.
The sample app continuously animates a rotating box on the main thread and, upon request, uses a web worker to calculate the Fibonacci sequence. You can see in the above performance snapshot how the animation process continues to occur at its regular intervals (indicated by the arrows), even as the worker thread is triggered, performs its tasks, and sends the payload back to the main thread.
Please let us know if you try out the sample app! You’re welcome to fork it as a template for your own projects and/or experiments.
If you've been using web workers at your organization, or if this article made you think of a possible use case for them, let us know in the comments! You can also visit our toolkit page, which gives solutions to technical or business issues and allows developers to focus on business needs.