浅谈Web Workers

1、简介前端

Web Workers是在HTML5中新增的,用来在Web应用程序中实现后台处理的一种技术。经过Web Workers你能够建立一个不会影响前台处理的后台线程,而且在这个后台线程中建立多个子线程。经过Web Workers,你能够将耗时较长的处理交给后台线程去运行,从而解决了HTML5以前由于某个处理耗时过长而跳出一个提示用户脚本运行时间过长,致使用户不得不结束这个处理的尴尬情况。git

 

2、分类github

Web workers可分为两种类型:专用线程dedicated web worker,以及共享线程shared web worker。 Dedicated web worker随当前页面的关闭而结束;这意味着Dedicated web worker只能被建立它的页面访问。与之相对应的Shared web worker能够被多个页面访问。在Javascript代码中,“Worker”类型表明Dedicated web worker,而“SharedWorker”类型表明Shared web worker。web

 

3、Worker对象使用数组

3.1 经常使用API服务器

1. 建立后台线程:session

在Worker类的构造器中,将须要在后台线程中执行的脚本文件的URL地址做为参数,而后建立Worker对象就能够了。app

var worker=new Worker("SumCalculate.js");

注意:在后台线程中是不能访问页面或窗口对象的。若是在后台线程的脚本文件中使用到window对象或者document对象,会引起错误。dom

2. 接收消息:socket

经过对Worker对象的onmessage事件句柄的获取能够在后台线程中接收消息。

worker.onmessage = function(event){

    //处理收到的消息

};

3. 发送消息:

使用Worker对象的postMessage方法来对后台线程发送消息,发送的消息能够是文本数据,也能够是任何JavaScript对象(须要经过JSON对象的stringify方法将其转换成文本数据)。

worker.postMessage(message);

一样能够经过获取Worker对象的onmessage事件和postMessage方法在后台线程内部进行消息的接收和发送。

4. terminate()

主线程中终止worker,此后没法再利用其进行消息传递。注意:一旦terminate后,没法从新启用,只能另外建立。

worker.terminate();

5. error()

出错处理。且错误消息能够经过e.message来获取。

worker.onerror = function(e){     
    //打印出错消息     
    console.log(e.message);     
    //中断与子线程的联系     
    worker.terminate(); 
}

 

4、 与线程进行数据的交互

1. 前端页面js代码

var intArray=new Array(100);
var intStr="";
for (var i=0;i<100;i++){
    intArray[i]=parseInt(Math.random()*100);
    if(i!=0){
        intStr+=";";
    }
    intStr+=intArray[i];
}

var worker=new Worker("script.js");
worker.postMessage(intStr);
worker.onmessage=function(event){
    if(event.data!=""){
        var j,k,tr,td,intArray=event.data.split(";"),
                table=document.getElementById("table");
        for(var i=0;i<intArray.length;i++){
            j=parseInt(i/10,0);
            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";
        }
    }
}

2. 后台线程代码,放在一个js文件中

onmessage=function(event){
    var data=event.data;
    var returnStr="";
    var intArray=data.split(";");
    for(var i=0;i<intArray.length;i++){
        if(parseInt(intArray[i])%3==0){
            if(returnStr!=""){
                returnStr+=";";
            }
            returnStr+=intArray[i]
        }
    }
    postMessage(returnStr);
}

在该示例中页面上随机生成了一个整数数组,而后将该正数数组传入线程,挑选出该数组中能够被3整除的数字,而后显示在页面的表格中。

 

5、线程嵌套

线程中能够嵌套子线程,这样的话咱们能够把一个较大的后台线程切分红几个子线程,在每一个子线程中各自完成相对独立的一部分工做。

示例:该示例中修改了前面所述与线程进行数据的交互中的示例,把生成随机数组的工做也放到后台线程中,而后使用一个子线程在随机数组中挑选能够被3整除的数字。代码以下:

1. 前端页面js代码

var worker=new Worker("script.js");
worker.postMessage(" ");
worker.onmessage=function(event){
    if(event.data!=""){
        var j,k,tr,td,intArray=event.data.split(";"),
                table=document.getElementById("table");
        for(var i=0;i<intArray.length;i++){
            j=parseInt(i/10,0);
            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";
        }
    }
}

2. 后台线程代码,放在一个js文件中

onmessage=function(event){
    var intArray=new Array(100);
    for (var i=0;i<100;i++){
        intArray[i]=parseInt(Math.random()*100);
    }
    var worker=new Worker("worker2.js");
    worker.postMessage(JSON.stringify(intArray));
    worker.onmessage=function(event){
            postMessage(event.data);
    }
}

在线程中,向子线程提交消息时使用子线程对象的postMessage方法,而向本线程的建立源发送消息时直接使用postMessage方法。

3.子线程代码,放在一个js文件中

onmessage = function(event){
    var intArray = JSON.parse(event.data);
    var returnStr;
    returnStr="";
    for(var i=0;i<intArray.length;i++){
        if(parseInt(intArray[i])%3 == 0){
            if(returnStr!=""){
                returnStr+=";"
            }
            returnStr+=intArray[i];
        }
    }
    postMessage(returnStr);
    close();
}

注意:在子线程中向发送源发送回消息后,若是该子线程再也不使用,最好使用close语句关闭子线程。

 

6、在多个子线程中进行数据的交互

要实现子线程与子线程之间的交互,大体须要以下几个步骤:

1)先建立发送数据的子线程。

2)执行子线程中任务,而后把要传递的数据发送给主线程。

3)在主线程接收到子线程传回来的消息时,建立接收数据的子线程,而后把发送数据的子线程中返回的消息传递给接收数据的子线程。

4)执行接收数据子线程中的代码。

1. 主线程代码

onmessage=function(event){
    var worker=new Worker("worker1.js");
    worker.postMessage("");
    worker.onmessage=function(event){
        var data = event.data;
        worker = new Worker("worker2.js");
        worker.postMessage(data);
        worker.onmessage=function(event){
            var data = event.data;
            postMessage(data);
        }
    }
}

2. 发送数据子线程代码

onmessage=function(event){
    var intArray=new Array(100);
    for(var i=0;i<100;i++){
        intArray[i]=parseInt(Math.random()*100);
    }
    postMessage(JSON.stringify(intArray));
    close();
}

3. 接收数据子线程代码

onmessage=function(event){
    var intArray = JSON.parse(event.data);
    var returnStr;
    returnStr="";
    for(var i=0;i<intArray.length;i++){
        if(parseInt(intArray[i])%3 == 0){
            if(returnStr!=""){
                returnStr+=";"
            }
            returnStr+=intArray[i];
        }
    }
    postMessage(returnStr);
    close();
}

 

7、线程中可用的变量、函数与类

  1. self:用来表示本线程范围内的做用域
  2. postMessage:用于向建立线程的源窗口发送消息
  3. onmessage:获取接收消息的事件
  4. importScripts(urls):导入其余JavaScript脚本文件。参数为该脚本文件的url地址,能够导入多个脚本文件。导入的脚本文件必须与使用该线程文件的页面在同一个域中,且在同一个端口中。
  5. navigator对象:与window.navigator对象相似,具备appName,platform,userAgent,appVersion属性。
  6. sessionStorage/localStorage:能够在线程中使用Web Storage
  7. XMLHttpRequest:能够在线程中处理Ajax请求
  8. Web Workers:能够在线程中嵌套线程
  9. setTimeout/setInterval:能够在线程中实现定时处理
  10. close:用于结束本线程
  11. eval,isNaN,escape等可使用全部JavaScript核心函数
  12. object:能够建立和使用本地对象
  13. Websockets:可使用WebSockets API来向服务器发送和接收消息
  14. FileSystem:能够在线程中经过同步FileSystem API来实现受沙箱保护的文件系统中的文件及目录的建立、更新及删除操做

 

8、SharedWorker使用

1. 建立SharedWorker对象

var worker = new SharedWorker(url,[name]);

其中第一个参数指定后台脚本文件的URL地址,第二个参数为可选参数,用于指定Worker的名称。

var worker = new SharedWorker('test.js');

2. 当SharedWorker对象被建立时,一个MessagePort对象也同时被建立,能够经过SharedWorker对象的port属性来访问该对象,该对象表示页面通讯时须要使用的窗口,具备以下所示的三个方法:

postMessage方法:用于向另外一个页面发送消息

start方法:用于激活端口,开始监听端口是否接收到消息

close方法:用于关闭并停用窗口

每一个MessagePort对象都具备一个message事件,当端口接收到消息时触发该事件。

能够经过监听MessagePort对象的message事件并指定事件处理函数的方法来指定在该端口接收到消息时所作的处理。

port.onmessage=function(event){

    //处理收到的消息

}

也能够经过MessagePort对象的addEventListener方法来监听message事件的触发,但在这种状况下必须使用MessagePort对象的start方法显式的激活端口,开始消息的监听

port.addEventListener('message', function(event){

    //处理收到的消息

},false);

port.start();

3. 当某个页面经过SharedWorker对象与共享后台线程开始通讯时,会触发后台线程对象的connect事件,能够监听该事件而且在后台脚本文件中定义该事件触发时所作的处理

onconnect=function(event){

    //定义事件处理函数

}

在事件处理函数中,event参数值(表明被触发的事件对象)的port属性值为一个集合,其中第一个数组即为该页面中的SharedWorker对象的port属性值,即表明该页面用于发送或者获取消息的端口的MessagePort对象。

onconnect=function(e){

    var port=e.ports[0];

    port.onmessage=function(e){

        port.postMessage(e.data*e.data);

    }

}

 参考书籍:《HTML5与CSS3权威指南》

样例代码能够去个人github下载:https://github.com/sakuramoon0203/Web-Worker

相关文章
相关标签/搜索