淺談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

相關文章
相關標籤/搜索