Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
143023864X_HT5.pdf
Скачиваний:
8
Добавлен:
21.02.2016
Размер:
7.98 Mб
Скачать

CHAPTER 10 USING THE WEB WORKERS API

Building an Application with Web Workers

So far, we’ve focused on using the different Web Worker APIs. Let’s see how powerful the Web Workers API can really be by building an application: a web page with an image-blurring filter, parallelized to run on multiple Web Workers. Figure 10-5 shows what this application looks like when you start it.

Figure 10-5. Web Worker–based web page with image-blurring filter

This application sends image data from a canvas to several Web Workers (you can specify how many). The Web Workers then process the image with a simple box-blur filter. This may take several seconds, depending on the size of the image and the computational resources available (even machines

250

CHAPTER 10 USING THE WEB WORKERS API

with fast CPUs may have load from other processes, causing JavaScript execution to take more wallclock time to complete). Figure 10-6 shows the same page after running the blur filtering process for a while.

Figure 10-6. Image-blurring web page after running for a while

However, because the heavy lifting takes place in Web Workers, there is no danger of slow-script warnings and, therefore, no need to manually partition the task into scheduled slices—something you would have to consider if you could not use Web Workers.

251

CHAPTER 10 USING THE WEB WORKERS API

Coding the blur.js Helper Script

Inside the blur.js application page, we can use a straightforward implementation of a blur filter that loops until it has completely processed its input, as shown in Listing 10-4.

Listing 10-4. A JavaScript Box-blur Implementation in the File blur.js

function inRange(i, width, height) {

return ((i>=0) && (i < width*height*4));

}

function averageNeighbors(imageData, width, height, i) { var v = imageData[i];

// cardinal directions

var north = inRange(i-width*4, width, height) ? imageData[i-width*4] : v; var south = inRange(i+width*4, width, height) ? imageData[i+width*4] : v; var west = inRange(i-4, width, height) ? imageData[i-4] : v;

var east = inRange(i+4, width, height) ? imageData[i+4] : v;

// diagonal neighbors

var ne = inRange(i-width*4+4, width, height) ? imageData[i-width*4+4] : v; var nw = inRange(i-width*4-4, width, height) ? imageData[i-width*4-4] : v; var se = inRange(i+width*4+4, width, height) ? imageData[i+width*4+4] : v; var sw = inRange(i+width*4-4, width, height) ? imageData[i+width*4-4] : v;

// average

var newVal = Math.floor((north + south + east + west + se + sw + ne + nw + v)/9);

if (isNaN(newVal)) {

sendStatus("bad value " + i + " for height " + height); throw new Error("NaN");

}

return newVal;

}

function boxBlur(imageData, width, height) { var data = [];

var val = 0;

for (var i=0; i<width*height*4; i++) {

val = averageNeighbors(imageData, width, height, i); data[i] = val;

}

return data;

}

In brief, this algorithm blurs an image by averaging nearby pixel values. For a large image with millions of pixels, this takes a substantial amount of time. It is very undesirable to run a loop such as this in the UI thread. Even if a slow-script warning did not appear, the page UI would be unresponsive until the loop terminated. For this reason, it makes a good example of background computation in Web Workers.

252

CHAPTER 10 USING THE WEB WORKERS API

Coding the blur.html Application Page

Listing 10-5 shows the code for the HTML page that calls the Web Worker. The HTML for this example is kept simple for reasons of clarity. The purpose here is not to build a beautiful interface, but to provide a simple skeleton that can control the Web Workers and demonstrate them in action. In this application, a canvas element that displays the input image is injected into the page. We have buttons to start blurring the image, stop blurring, reset the image, and specify the number of workers to spawn.

Listing 10-5. Code for the Page blur.html

<!DOCTYPE html>

<title>Web Workers</title>

<link rel="stylesheet" href = "styles.css">

<h1>Web Workers</h1>

<p id="status">Your browser does not support Web Workers.</p>

<button id="startBlurButton" disabled>Blur</button> <button id="stopButton" disabled>Stop Workers</button>

<button onclick="document.location = document.location;">Reload</button>

<label for="workerCount">Number of Workers</label> <select id="workerCount">

<option>1</option>

<option selected>2</option> <option>4</option> <option>8</option> <option>16</option>

</select>

<div id="imageContainer"></div> <div id="logOutput"></div>

Next, let’s add the code to create workers to the file blur.html. We instantiate a worker object, passing in a URL of a JavaScript file. Each instantiated worker will run the same code but be responsible for processing different parts of the input image:

function initWorker(src) {

var worker = new Worker(src); worker.addEventListener("message", messageHandler, true); worker.addEventListener("error", errorHandler, true); return worker;

}

Let’s add the error handling code to the file blur.html, as follows. In the event of an error in the worker, the page will be able to display an error message instead of continuing unaware. Our example shouldn’t encounter any trouble, but listening for error events is generally a good practice and is invaluable for debugging.

function errorHandler(e) {

253