您的位置:首页 > Web前端 > HTML5

HTML5编程之旅 第5站Web Workers

2014-02-28 11:07 295 查看
HTML5 Web Workers可以使得你的Web应用程序具备后台处理能力,能够支持多线程,且可以充分利用多核CPU带来的优势。以避免JavaScript循环持续运行后弹出的警告窗口。

尽管Web Workers功能强大,但是也存在一些缺点,比如不能直接访问Web页面和DOM API、消耗CPU周期且导致系统反应速度变慢。

如果需要Web应用执行一些后台数据处理,但又不影响Web页面本身的交互时,就可以使用Web Workers,同时需要添加一个监听器以监听它发出的消息。

一、HTML5 Web Workers API概述

1、浏览器支持检查

typeof(Worker) !== "undefined"


2、创建HTML5 Web Workers

Web Workers初始化时会接受一个JavaScript文件的URL地址(URL可以是绝对或者相对路径,但必须同源),其中包含了供Worker执行的代码。这段代码会设置事件监听器,并与生成Worker的容器进行通信。

worker = new Worker("echoWorker.js");


3、多个JavaScript文件的加载与执行

由于Web Workers没有访问document对象的权限,因此不能使用常规导入JavaScript的方式,需要另一种方法来导入JavaScript,即importScripts:

importScripts("helper.js","example.js","blur.js");


多个脚本的导入会按照导入顺序执行。

4、与HTML5 Web Workers通信

Web Workers一旦生成,就可以使用postMessage API传送和接收数据。

为了能与Web Workers成功通信,除了在主页(调用Web Workers的页面)中添加代码外,Worker JavaScript文件中也要添加相应代码。

二、Web Workers示例应用

1、建立主页与Web Workers之间的通信

首先要添加对postMessage函数的调用,如下所示:

worker.postMessage("发送示例消息");


相应消息发送给Web Workers后,还需要添加监听器,用以监听Web Workers发来的消息

worker.addEventListener("message",messageHandler,true);
function messageHandler(e){
//处理worker发来的消息
}


在Web Workers JavaScript文件中,也需要添加上述类似的代码:必须添加事件监听器来监听发来的消息和错误消息,并且通过用postMessage函数实现与页面之间的通信。

2、处理错误

监听到错误事件发生后,要将出错信息反馈给用户:

function errorHandler(e){
console.log(e.message,e);
}


3、终止Web Workers

worker.terminate();


终止之后的Web Workers不能被重新启动,但可以使用同样的URL创建一个新的Worker。

4、示例代码整合

本示例实现 一个带有图像模糊过滤器的Web页面,其中过滤动作将由多个Web Worker并发执行。

(1)编写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;
}


(2)编写blur.html页面

<!DOCTYPE html>
<title>HTML5 Web Workers</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href = "styles.css">

<h1>HTML5 Web Workers</h1>

<p id="status">你的浏览器不支持HTML5 Web Workers.</p>

<button id="startBlurButton" disabled>模糊</button>
<button id="stopButton" disabled>停止Workers</button>
<button onclick="document.location = document.location;">重新加载</button>

<label for="workerCount">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>


(3)编写blurWorker.js

importScripts("blur.js");

function sendStatus(statusText){
postMessage({"type" : "status",
"statusText" : statusText});

}
function messageHandler(e){
var messageType = e.data.type;
switch(messageType){
case ("blur"):
sendStatus("Worker开始模糊的数据范围: " +
e.data.startX + "-" + (e.data.startX+e.data.width));
var imageData = e.data.imageData;
imageData = boxBlur(imageData, e.data.width, e.data.height, e.data.startX);
postMessage({"type" : "处理",
"imageData" : imageData,
"width" : e.data.width,
"height" : e.data.height,
"startX" : e.data.startX
});
sendStatus("在数据范围: " +
e.data.startX + "-" + (e.data.width+e.data.startX) + "完成数据模糊");
break;
default:
sendStatus("Worker获得消息:" + e.data);
}
}

addEventListener("message", messageHandler, true);


(4)与Web Workers进行通信

function sendBlurTask(worker, i, chunkWidth) {
var chunkHeight = image.height;
var chunkStartX = i * chunkWidth;
var chunkStartY = 0;
var data = ctx.getImageData(chunkStartX, chunkStartY,
chunkWidth, chunkHeight).data;

worker.postMessage({'type' : 'blur',
'imageData' : data,
'width' : chunkWidth,
'height' : chunkHeight,
'startX' : chunkStartX});
}


(5)示例代码

<!DOCTYPE html>
<title>HTML5 Web Workers</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href = "styles.css">

<h1>HTML5 Web Workers</h1>

<p id="status">你的浏览器不支持HTML5 Web Workers.</p>

<button id="startBlurButton" disabled>模糊</button>
<button id="stopButton" disabled>停止Workers</button>
<button onclick="document.location = document.location;">重新加载</button>

<label for="workerCount">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>
<script>
var imageURL = "example2.png";
var image;
var ctx;
var workers = [];
window.addEventListener("load", loadDemo, true);
function loadDemo(){
log("加载图像数据");
if(typeof(Worker) !== "undefined"){
document.getElementById("status").innerHTML = "你的浏览器支持HTML5 Web Workers";

document.getElementById("stopButton").onclick = stopBlur;
document.getElementById("startBlurButton").onclick = startBlur;

loadImageData(imageURL);

document.getElementById("startBlurButton").disabled = true;
document.getElementById("stopButton").disabled = true;
}
}
function log(s){
var logOutput = document.getElementById("logOutput");
logOutput.innerHTML = s + "<br>" + logOutput.innerHTML;
}
function loadImageData(url){
var canvas = document.createElement('canvas');
ctx = canvas.getContext('2d');
image = new Image();
image.src = url;
document.getElementById("imageContainer").appendChild(canvas);
image.onload = function(){
canvas.width = image.width;
canvas.height = image.height;
ctx.drawImage(image, 0, 0);
window.imgdata = ctx.getImageData(0, 0, image.width, image.height);
n = ctx.createImageData(image.width, image.height);
setRunningState(false);
log("图像加载:" + image.width + "x" + image.height + "pixels");
}
}
function setRunningState(p){
document.getElementById("startBlurButton").disabled = p;
document.getElementById("stopButton").disabled = !p;
}
function stopBlur(){
for(var i=0; i<workers.length; i++){
workers[i].terminate();
}
setRunningState(false);
}
function startBlur(){
var workerCount = parseInt(document.getElementById("workerCount").value);
var width = image.width/workerCount;
for(var i=0; i<workerCount; i++){
var worker = initWorker("blurWorker.js");
worker.index = i;
worker.width = width;
workers[i] = worker;
sendBlurTask(worker, i, width);
}
setRunningState(true);
}
function initWorker(src){
var worker = new Worker(src);
worker.addEventListener("message",messageHandler, true);
worker.addEventListener("error",errorHandler, true);
return worker;
}
function messageHandler(e) {
var messageType = e.data.type;
switch (messageType) {
case ("status"):
log(e.data.statusText);
break;
case ("progress"):
var imageData = ctx.createImageData(e.data.width, e.data.height);

for (var i = 0; i<imageData.data.length; i++) {
var val = e.data.imageData[i];
if (val === null || val > 255 || val < 0) {
log("illegal value: " + val + " at " + i);
return;
}

imageData.data[i] = val;
}
ctx.putImageData(imageData, e.data.startX, 0);

// blur the same tile again
sendBlurTask(e.target, e.target.index, e.target.width);
break;
default:
break;
}
}

function errorHandler(e) {
log("error: " + e.message);
}

function sendBlurTask(worker, i, chunkWidth) { var chunkHeight = image.height; var chunkStartX = i * chunkWidth; var chunkStartY = 0; var data = ctx.getImageData(chunkStartX, chunkStartY, chunkWidth, chunkHeight).data; worker.postMessage({'type' : 'blur', 'imageData' : data, 'width' : chunkWidth, 'height' : chunkHeight, 'startX' : chunkStartX}); }

</script>


源码请到http://git.oschina.net/niweiwei/HTML5/tree/master/workers查看
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: