Thursday, March 28, 2024

Introduction to HTML5 Web Workers: Use Cases and Identify Hot Spots

written by David Rousset

Previously we introduced HTML5 Web Workers, showed you how to post messages using JSON, and discussed web browsers support, non-accessible elements, and error handling & debugging. This week we will look at use cases and specific scenarios for the use of Web Workers, and will show you how to locate hot spots within your code.

Use Cases and How to Identify Potential Candidates

When you browse the Web looking for sample usages of the Web Workers, you always find the same kind of demos: intensive mathematical/scientific computation. You’ll then find some JavaScript raytracers, fractals, prime numbers, and stuff like that. Nice demos to understand the way Workers works, but this gives us few concrete perspectives on how to use them in “real world” applications.

Web Workers for Which Scenarios?

It’s true that the limitations we’ve seen above on the resources available inside Web Workers narrow down the number of interesting scenarios. Still, if you just take some time to think about it, you’ll start to see new interesting usages:

  • image processing by using the data extracted from the <canvas> or the <video> elements. You can divide the image into several zones and push them to the different Workers that will work in parallel. You’ll then benefit from the new generation of multi-cores CPUs. The more you have, the faster you’ll go.
  • big amount of data retrieved that you need to parse after an XMLHTTPRequest call. If the time needed to process this data is important, you’d better do it in background inside a Web Worker to avoid freezing the UI Thread. You’ll then keep a reactive application.
  • background text analysis: as we have potentially more CPU time available when using the Web Workers, we can now think about new scenarios in JavaScript. For instance, we could imagine parsing in real-time what the user is currently typing without impacting the UI experience. Think about an application like Word (of our Office Web Apps suite) leveraging such possibility: background search in dictionaries to help the user while typing, automatic correction, etc.
  • concurrent requests against a local database. IndexDB will allow what the Local Storage can’t offer us: a thread-safe storage environment for our Web Workers.

Moreover, if you switch to the video game world, you can think about pushing the AI or physics engines to the Web Workers. For instance, I’ve found this experimentation: On Web Workers, GWT, and a New Physics Demo which use the Box2D physic engine with Workers. For your Artificial Intelligence engine, this means also that you will be able in the same timeframe to process more data (anticipate more moves in a chess game for instance).

Some of my colleagues may now argue that the only limit is your imagination!

But in a general manner, as long as you don’t need the DOM, any time-consuming JavaScript code that may impact the user experience is a good candidate for the Web Workers. However, you need to pay attention to 3 points while using the Workers:

  1. The initializing time and the communication time with the worker shouldn’t be superior to the processing itself
  2. The memory cost of using several Workers
  3. The dependency of the code blocks between them as you may then need some synchronization logic. Parallelization is not something easy my friends!

On our side, we’ve recently published the demo named Web Workers Fountains:

Image 1

This demo displays some particles effects (the fountains) and uses 1 Web Worker per fountain to try to compute the particles in the fastest way possible. Each Worker result is then aggregated to be displayed inside the <canvas> element. Web Workers can also exchange messages between them via the Message Channels. In this demo, this is used to ask to each of the Workers when to change the color of the fountains. We’re then looping through this array of colors: red, orange, yellow, green, blue, purple, and pink, thanks to the Message Channels. If you’re interested in the details, jump into the LightManager() function of the Demo3.js file.

Also, feel free to launch this demo inside Internet Explorer 10, it’s fun to play with!

How To Identify Hot Spots in Your Code

To track the bottlenecks and identify which parts of your code you could send to the Web Workers, you can use the script profiler available with the F12 bar of IE9/10. It will then help you to identify your hot spots. However, identifying a hot spot doesn’t mean you’ve identified a good candidate for Web Workers. To better understand that, let’s review together two different interesting cases.

Case 1: Animation inside <canvas> with the Speed Reading demo

This demo comes from IE Test Drive and can be browsed directly here: Speed Reading. It tries to display some characters as fast as possible using the <canvas> element. The goal is to stress the quality of the implementation of the hardware acceleration layer of your browser. But going beyond that, would it be possible to obtain more performance by splitting some operations on threads? We need to achieve some analysis to check that.

If you run this demo inside IE9/10, you can also start the profiler within a couple of seconds. Here is the kind of results you’ll obtain:

Image 2

If you’re sorting the time-consuming functions in decreasing order, you’ll clearly see those functions coming first: DrawLoop(), Draw() and drawImage(). If you’re double-clicking on the Draw line, you’ll jump into the code of this method. You’ll then observe several calls of this type:

surface.drawImage(imgTile, 0, 0, 70, 100, this.left, this.top, this.width, this.height);

Where the surface object is referencing a <canvas> element.

A quick conclusion of this brief analysis is that this demo spends most of its time drawing inside the Canvas through the drawImage() method. As the <canvas> element is not accessible from a Web Worker, we won’t be able to offload this time-consuming task to different threads (we could have imagined some ways of handling the <canvas> element in a concurrency manner for instance). This demo is then not a good candidate for the parallelization possibilities offered by the Web Workers.

It’s well-illustrating the process you need to put in place, however. If, after a profiling job, you’re discovering that the major part of the time-consuming scripts are deeply linked to DOM objects, the Web Workers won’t be able to help you boost the performance of your Web app.

Case 2: Raytracers inside <canvas>

Let’s now take another easy example to understand. Let’s take a raytracer like this one: Flog.RayTracer Canvas Demo. A raytracer uses some very CPU-intensive mathematical computations in order to simulate the path of light. The idea is to simulate some effects like reflection, refraction, materials, etc.

Let’s render a scene while launching the script profiler. You should obtain something like this:

Image 3

Again, if we sort the functions in decreasing order, 2 functions clearly seem to take most of the time: renderScene() and getPixelColor().

The goal of the getPixelColor() method is to compute the current pixel. Indeed, ray-tracing is rendering a scene pixel per pixel. This getPixelColor() method is then calling the rayTrace() method in charge of rendering the shadows, ambient light, etc. This is the core of our application. And if you’re reviewing the code of the rayTrace() function, you’ll see that it’s 100% pure JavaScript juice. This code has no DOM dependency. Well, I think you’ll get it: this sample is a very good candidate to parallelization. Moreover, we can easily split the image rendering on several threads (and thus potentially on several CPUs) as there’s no synchronization needed between each pixel computation. Each pixel operation is independent from its neighborhood as no anti-aliasing is used in this demo.

This is then not a surprise if we can find some raytracers samples using some Web Workers like this one.

After profiling this raytracer using IE10, we can see the important differences between using no Worker and using 4 Workers:

Image 4

In the first screenshot, the processRenderCommand() method is using almost all of the CPU available and the scene is rendered in 2.854s.

With 4 Web Workers, the processRenderCommand() method is executed in parallel on 4 different threads. We can even see their Worker Id on the right column. The scene is rendered this time in 1.473s. The benefits were real: the scene has been rendered 2 times faster.

Conclusion

There is no magical or new concept linked to the Web Workers in the way to review/architect your JavaScript code for parallel execution. You need to isolate the intensive part of your code. It needs to be relatively independent of the rest of your page’s logic to avoid waiting for synchronization tasks. And the most important part: the code shouldn’t be linked to the DOM. If all these conditions are met, think about the Web Workers. They could definitely help you boost the general performance of your Web app!

Additional Web Worker Resources

Here are some interesting additional resources to read:

About the Author

David Rousset is a Developer Evangelist at Microsoft, specializing in HTML5 and web development. Follow him @Silversurfeur on Twitter.

This article was reprinted with permission from Microsoft Corporation. This site does business with Microsoft Corporation.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Popular Articles

Featured