深刻理解Web Workers

一.Web Workers是什麼

Web Workers是JavaScript運行在瀏覽器中的一種能力,它容許在主線程建立Worker線程,主線程執行的同時,Worker線程在後臺運行,互不干擾,這並非說JavaScript自己具備多線程的能力,是js運行在webkit瀏覽器中,瀏覽器爲其啓動了新的線程,從而實現多線程的功能.html

二.Web Workers分類

Web Workers中主要的兩種線程爲專用線程Dedicated Worker和共享線程 Shared Worker,專用線程供單頁面使用,即專用線程不能被多個不一樣的頁面使用,共享線程能被多個不一樣的頁面使用.web

2.1.專用線程(Dedicated Worker)算法

2.1.1專用線程實例json

在輸入框輸入一個數,計算出從1到該數字的和

(1).主線程代碼canvas

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
  </head>
  <body>
    <div class="web-worker">
      <input type="text" placeholder="請輸入要計算到的數字" id="num" />
      <button onclick="calculate()">計算</button>
    </div>
  </body>
  <script>
  function calculate() {
    var dom = document.getElementById("num");
    var value = parseInt(dom.value, 10);
    worker.postMessage(value);
  }

  var worker = new Worker("worker.js");
  worker.onmessage = function(event) {
    console.log("receive data", event.data);
    worker.terminate(); //終止worker進程
  }
  worker.onerror = function(error) {
    console.log("error==", error.message, error.filename, error.lineno); 
    //error錯誤信息:message返回可讀性良好的錯誤消息;filename發生錯誤的腳本文件名;lineno發生錯誤時所在腳本文件的行號
  }
  </script>
</html>

(2).Worker線程代碼(Worker線程代碼寫在worker.js中)segmentfault

onmessage = function(event) {
  console.log("worker event data", event.data);
  var value = event.data;
  var sum = 0;
  for (var i = 1; i < value; i++) {
    sum += i;
  }
  postMessage(sum);
}

(3).執行結果:
clipboard.png跨域

2.1.2線程執行深度解析
根據以上述實例說明
(1).首先調用Worker的構造函數新建一個worker,指定一個腳本URI去執行worker線程
(2).經過postMessage發送給worker線程
(3).在worker線程中用onmessage監聽消息數據,並接收封裝在event參數data屬性中的數據
(4).worker將處理過的數據再經過postMessage發送給主線程
(5).worker線程返回數據後,執行主線程的onmessage回調函數,調用worker.terminate()終止線程執行,當worker線程執行出錯時會調用onerror回調函數.瀏覽器

詳解:
代碼執行到 var worker = new Worker("worker.js"),會在webkit內核中構造一個webCore::jsWorker對象,並根據腳本地址發起異步加載流程,此時主線程並不會阻塞,等待worker線程的執行結果,而是會接着往下執行.接着主線程執行postMessage,這時worker線程還麼有建立完成,經過input輸入框輸入的數據將放在消息隊列中等待,直到worker線程建立完畢;worker線程複製消息數據到workerRunLoop消息隊列中,woker線程處理消息數據後將數據經過自身的postMessage發送,主線程執行worker.onmessage回調函數,執行完畢後關閉線程.若是主線程接着給worker線程發送數據消息,worker線程會直接將複製消息數據到WorkerRunLoop.如圖所示緩存

clipboard.png

2.1.3Transferrable objects可轉讓對象
主線程和子線程之間能夠經過結構化克隆算法(複製副本)的方式傳入傳出不一樣類型數據,好比File,Blob,ArrayBuffer和json對象,若是用postMessag傳出一個50MB的文件將會很是消耗性能,爲了解決這個問題,能夠將主線程中的數據直接傳遞給worker線程這就是Transferrable objects.服務器

// Transferable Objects 格式
worker.postMessage(arrayBuffer, [arrayBuffer]);

// 例子1
var ab = new ArrayBuffer(1);
worker.postMessage(ab, [ab]);
//例子2
var uInt8Array = new Uint8Array(1024*1024*32); // 32MB
for (var i = 0; i < uInt8Array .length; ++i) {
    uInt8Array[i] = i;
}
worker.postMessage(uInt8Array.buffer, [uInt8Array.buffer]);

2.1.4應用場景

(1).預先緩存並抓取數據供後期使用
(2).分析音視頻數據,canvas繪圖數據的運算和圖形生成處理
(3).大量數據分析和計算處理
(4).拼寫檢查
(5).代碼高亮處理或者其餘一些頁面文字格式化處理

2.1.5總結
學習專用線程,其實它能夠和生活中的例子相結合起來,好比領導給員工分配任務,讓A員工把產品的原型畫出來後交給B員工去實現(領導做爲主線程),A員工在接收到任務message後開始工做,工做的產出的原型就是postMessage要返回的數據,B員工在沒拿到原型時還作的他以前的工做,收到A員工給的原型開始實現原型,實現完成後將產出結果給領導演示.結合這個例子能夠理解專用線程的大體流程.

2.1.6兼容性

clipboard.png

2.2共享線程(Shared Worker)

2.2.1共享線程實例

兩個頁面分別給一個SharedWorker發送數據並接收同一個共享線程發送的數據
//A頁面js代碼
  var worker = new SharedWorker("./worker.js");
  var port = worker.port;
  console.log("test port", port);
  port.postMessage('test000');
  port.onmessage = function(event) {
    console.log("test receive data", event.data);
  }
//B頁面js代碼
  var worker = new SharedWorker('worker.js');
  var port = worker.port;
  console.log("worker1 port", port);
  port.postMessage('test111');
  port.onmessage = function(event) {
    console.log("test1 receive data", event.data);
  };
//worker.js(即SharedWorker)代碼
onconnect = function(event) {
  var port = event.ports[0];
  port.onmessage = function(e) {
    port.postMessage(e.data);
  }
}

執行結果:
clipboard.png
clipboard.png

2.2.2應用場景
共享線程主要用在同一個線程被多個頁面或線程使用,好比,抓取緩存數據多個頁面須要使用,在瀏覽器兼容的狀況下可使用ShareWorker.

2.2.3總結
在測試上述例子時,用google瀏覽器測試,共享線程中的例子不執行,但願能獲得解答和幫助

2.2.4兼容性

clipboard.png

三.專用線程和共享線程的區別和注意事項

3.1區別
(1)共享worker通訊必須經過端口對象(一個確切的打開的端口)供腳本與worker通訊,而專用線程在設置onmessage消息處理函數時會隱式的打開與主線程的端口鏈接.
3.2注意事項

(1).在寫demo測試時,Google瀏覽器直接打開文件,會當成是跨域問題,報相似以下錯誤,啓用本地服務器測試就能夠了,用Node啓用本地服務器,能夠看個人另外一個文章 https://segmentfault.com/a/11...
clipboard.png

(2)分配給 Worker 線程運行的腳本文件,必須與主線程的腳本文件同源。

(3)worker線程不能獲取DOM,window,document,parent對象,能夠獲取navigator,Location,XMLHttpRequest對象,setInterval/setTimeout方法, Application Cache,能夠經過importScripts()方法加載其餘腳本,能夠建立新的Web Worker。

四.其餘類型Worker

4.1 ServiceWorkers (服務worker)

通常做爲web應用程序、瀏覽器和網絡(若是可用)以前的代理服務器。它們旨在(除開其餘方面)建立有效的離線體驗,攔截網絡請求,以及根據網絡是否可用採起合適的行動並更新駐留在服務器上的資源。他們還將容許訪問推送通知和後臺同步API。

4.2 Chrome Workers

是一種僅適用於firefox的worker。若是您正在開發附加組件,但願在擴展程序中使用worker且有在你的worker中訪問 js-ctypes 的權限,你可使用Chrome Workers。詳情請參閱ChromeWorker。

4.3 Audio Workers (音頻worker)

使得在web worker上下文中直接完成腳本化音頻處理成爲可能。

望不對之處請指正!

主要參考文章:

1. http://www.alloyteam.com/2015...
2. https://developer.mozilla.org...
3. http://www.ruanyifeng.com/blo...
相關文章
相關標籤/搜索