Canvas API is used to run graphics, animations, and other exciting things on your website. But running these operations can be resource-intensive and slow down the responsiveness of the user interface.
Canvas operations used to be executed strictly on the main thread since they relied on the canvas
HTML element, which required access to the DOM. Fortunately, that’s no longer the case. In this tutorial, we’ll examine how OffScreenCanvas and Web Workers can help us improve canvas performance.
What is Web Workers API
Web workers are the means of achieving parallel execution in the browser. With them, you can run scripts in background threads.
Web workers allow you to run JavaScript code in the background, separately from the main UI thread. You can use them to improve your app’s performance and run tasks even if the browser is not focused on it.
The main thread and web workers can communicate by setting up event handlers and posting messages using the postMessage
method.
To learn more about web workers, check out this documentation page .
What is OffscreenCanvas
Web workers are great but have limited access to browser APIs. For example, you cannot directly manipulate DOM elements from within Web workers - it is only possible from the main thread.
Fortunately, that is where OffScreenCanvas
comes in! The OffscreenCanvas
interface is a canvas that can be rendered off-screen, separating it from the DOM.
OffScreenCanvas
is a transferable object, which means you can safely pass it to the web workers and run canvas operations on background threads. In order to send an OffScreenCanvas
instance to a worker, you use postMessage.
The OffScreenCanvas
can be synced with a regular canvas using the transferControlToOffscreen
function. Once you do that, the operations performed on the OffScreenCanvas will automatically transfer to the original canvas elements.
How To Set Up OffScreenCanvas with web workers
Now let’s see how we can use OffScreenCanvas
with web workers to boost performance.
Our project will have an index.js
file that kicks off the animation. Here’s what it looks like:
|
|
Pretty straightforward: when the script loads, it gets a reference to the <canvas/>
element in our index.html
file and creates an instance of the OffScreenCanvas using the transferControlToOffscreen
function.
As you can see, it also initiates our worker and calls the postMessage
on it twice: the first time to transfer the OffScreenCanvas instance to the worker and the second time to trigger the animation.
Now let’s take a look at what our worker script looks like:
|
|
Our worker script sets up a listener using the onmessage
function. When our worker receives messages from the main thread, it assigns canvasMessage
to its global canvas
variable. The second time it receives a message, it calls the animate
function to run the canvas animation.
Now, even if our main thread was to become busy and less responsive, that would not affect our worker’s execution. It would still run the animation and update our canvas. And vice-versa, the animation running in the web workers will not stop the UI thread from smoothly responding to user input.
Using it with other libraries
Another nice thing about OffScreenCanvas
is that you can use it to improve the performance of third-party graphics libraries that rely on canvas, like
three.js
. Since the OffscreenCanvas
API is generally compatible with the regular canvas
element.
But one thing to be aware of is that OffScreen canvas doesn’t have style.width
and style.height
properties that some of those libraries might need. In those cases, you can inject those properties in your OffScreenCanvas
instance before passing it to the library.
Conclusion
In this post, we covered how to use OffScreenCanvas to improve the performance of your canvas operations. OffScreenCanvas can be a great way to avoid some of these problems, and it’s simple to use.
To see the full code for this tutorial check out this codesandbox .
If you’d like to get more web development, React and TypeScript tips consider
following me on Twitter,
where I share things as I learn them.
Happy coding!