天天看点

HTML5 Web Worker(读书笔记)

最近看了《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学习的总结

继续阅读