最近看了《HTML5與CSS3權威指南》,了解下Web Worker,以下為書中第十章内容
(一)基礎知識
JavaScript建立的Web程式,處理都是在單線程内執行,花費時間較長,程式處于長時間沒有響應的狀态。例如下面例子:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<script type="text/javascript">
function calculate(){
var num=parseInt(document.getElementById("num").value,10);
var result=0;
for(var i=0;i<=num;i++){
result+=i;
}
alert("結果為"+result);
}
</script>
</head>
<body>
<h1>求和</h1>
輸入數值:<input type="text" id="num">
<button οnclick="calculate()">計算</button>
</body>
</html>
上述例子中,當輸入值較大,會彈出警告框
HTML5 新增一個Web Worker API。使用者可以容易地建立在背景的線程,将耗費較長時間的處理交給背景,使用者在前台頁面中執行的操作就完全沒有影響了。
1)建立背景程式
var worker=new Worker("worker.js");
背景程式線程中不能通路視窗對象和頁面,在背景線程的腳本檔案中使用document和window對象,會引起錯誤。
2)接收背景線程之中的消息
worker.onmessage=function(event)
{
//處理收到的消息
}
3)使用postMessage向背景線程發送消息
worker.postMessage(message);
發送的消息可以是文本資料,任何javascript對象(需要使用JSON的stringify方法将其轉換為文本資料)
Worker對象的onmessage事件句柄和postMessage事件句柄方法在背景線程内部進行消息的接收和發送
使用WebWorkers重寫上例,如下:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<script type="text/javascript">
//建立執行運算的線程
var worker=new Worker("SumCalculate.js")
//接受從線程中傳出的計算結果
worker.onmessage=function(event){
//消息文本放置在data屬性中,可以是任何javascript對象
alert("結果為:"+event.data);
};
function calculate(){
var num=parseInt(document.getElementById("num").value,10);
//将數值傳給線程
worker.postMessage(num);
}
</script>
</head>
<body>
<h1>求和</h1>
輸入數值:<input type="text" id="num">
<button οnclick="calculate()">計算</button>
</body>
</html>
其中,線程代碼單獨寫在SumCalculate.js中
onmessage=function(event){
var num=event.data;
var result=0;
for(var i=0;i<num;i++){
result+=i;
}
//向線程建立源送回消息
postMessage(result);
}
(二)與線程進行資料的互動以及線程嵌套
使用背景線程不能通路頁面和視窗對象,但背景線程可以和頁面之間進行資料互動。下面為一個從随機生成的數字中抽取3的倍數并顯示:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<script type="text/javascript">
//建立執行運算的線程
var worker=new Worker("worker1.js");
worker.postMessage("");
//接受從線程中取得的計算結果
worker.onmessage=function(event){
if(event.data!=""){
var j; //行号
var k; //列号
var tr;
var td;
var intArray=event.data.split(";");
var table=document.getElementById("table");
for(var i=0;i<intArray.length;i++){
j=parseInt(i/10,10);
k=i%10;
if(k==0){ //該行不存在
//添加行
tr=document.createElement("tr");
tr.id="tr"+j;
table.appendChild(tr);
} else{ //該行已經存在
//擷取該行
tr=document.getElementById("tr"+j);
}
//添加列
td=document.createElement("td");
tr.appendChild(td);
//設定該列的内容
td.innerHTML=intArray[j*10+k];
//設定該列背景色
td.style.backgroundColor="blue";
td.style.color="white";
td.width="30";
}
}
};
</script>
</head>
<body>
<h1>從随機生成的數字中抽取3的倍數并顯示比例</h1>
<table id="table"></table>
</body>
</html>
主線程worker1.js的代碼為
onmessage=function(event){
var intArray=new Array(100); //随機數組
//生成100個随機數
for(var i=0;i<100;i++){
intArray[i]=parseInt(Math.random()*100);
}
var worker;
//建立子線程
worker=new Worker("worker2.js");
//把随機數組送出給子線程進行挑選工作
worker.postMessage(JSON.stringify(intArray));
worker.onmessage=function(event){
//挑選結果傳回首頁面
postMessage(event.data);
}
}
子線程worker2.js的代碼為
onmessage=function(event){
//還原整數數組
var intArray=JSON.parse(event.data);
var returnStr="";
for(var i=0;i<intArray.length;i++){
//能否被3整除
if(parseInt(intArray[i])%3==0){
if(returnStr!="")
returnStr+=";";
//将能被3整除的數字拼接成字元串
returnStr+=intArray[i];
}
}
//傳回字元串
postMessage(returnStr);
//關閉子線程
close();
}
注:子線程向發送源發送回消息後,最好使用close關閉子線程,如果子線程不在使用。
(三)子線程與子線程之間的資料互動,大緻步驟如下:
1)先建立發送資料的子線程
2)執行子線程任務,把要傳遞的資料發送給主線程
3)在主線程接受到子線程傳遞回的消息時,建立接收資料的子線程,然後把發送資料的子線程中傳回的消息傳遞給接收資料的子線程
4)執行接收資料子線程中的代碼
以上為HTML5 Web Worker學習的總結