web worker入門指南

本文引用至: web worker
因爲瀏覽器的限制,註定了每一個網頁只能在一個進程程當中運行, 並且,js又只能運行在一個線程當中. 因此, 做爲一名開發者來講, 對於這樣的結果就只能呵呵了. 若是你想進行高複雜度的運算, 基本上就能夠go die了(只要運行, 你網頁基本上就崩掉了). 固然,聰明的W3C早就知道developer內心的小貓膩. 推出了web worker 這個概念. 咱們接下來,來正式接觸一下 web worker吧.html

初入web worker

web worker 既然是一個線程. 那一定會設計到線程間的通訊. 這裏,ww(web worker)提供了一個最簡單的方法--postMessage(msg) 進行雙向通訊.
來看一個簡單的Demo:react

// index.html 中的 main.js
var worker = new Worker('Worker.js');

worker.addEventListener('message', function(e) {
  console.log('Worker said: ', e.data);
}, false);

worker.postMessage('Hello World'); // Send data to our 

// Worker.js內容

self.addEventListener('message', function(e) {
  self.postMessage(e.data);
}, false);

當載入main.js時, 在Console裏,就會出現Hello World的內容. 上面的例子實際上,已經說明了worker的工做原理. 在worker中,self就是 new Wroker的實例化的內容.
不過, 這裏想強調一點, 經過postMessage傳遞的msg並非兩個線程共享的.(要是共享的,不就GG了) 傳遞的Msg其實是一個副本, 最具備表明性的,應該就算是Object.jquery

// main.js 傳遞一個Object
var worker = new Worker('Worker.js');

worker.addEventListener('message', function(e) {
  console.log('Worker said: ', msg.a);
}, false);
var msg = {
    a:2
}
worker.postMessage(msg);

// worker.js 接受,並返回
self.addEventListener('message', function(e) {
  e.data.a=3;
  self.postMessage(e.data);
}, false);

// 最後返回的結果是2

在一端向另一端傳遞msg時, 中間會通過serialized, 而後de-serialized 最終獲得結果. 通俗一點就是:web

// 傳遞前
JSON.stringify(msg);
// 解析數據
JSON.parse(msg);

當worker已經處理完畢,沒有多大卵用以後. 就能夠kill掉該線程.ajax

關閉worker

在web中, 提供了兩種方法來關閉Web Worker. 關閉指定的Worker以後, 至關於即,kill 掉該線程. 因此, 這裏須要注意一下:瀏覽器

  • worker.terminate(): 在外部終結該worker.併發

  • self.close(): 在worker內部自動終結.dom

官方推薦是,使用self.close進行內部的自動關閉. 這樣能防止, 意外關閉正在運行的worker.函數

worker做用域

上面,在worker.js中,咱們使用self來獲取worker自帶的方法.post

self.addEventListener('message', function(e) {
  self.postMessage(e.data);
}, false);

實際上, 在worker中, 他的全局索引就是self和this. 因此, 上面的代碼能夠簡寫爲:

addEventListener('message', function(e) {
  postMessage(e.data);
}, false);

worker 可訪問的 feature

worker 引用的就是js文件, 可能有些童鞋就會將worker當成通常js來使用. 可是,因爲worker是獨立的線程緣由,他和main js threading仍是有很大區別的.
他可以訪問的權限有:

  • The navigator object: window.navigator 相關屬性和方法

  • The location object (read-only): 只讀的window.location內容.

  • XMLHttpRequest: 臥槽... 能夠訪問這個那就不得了了. worker就能夠利用ajax來和後臺進行通訊了.

  • setInterval()相關時間函數

剩下的就是不能訪問的了。

錯誤處理

web worker 中的error handler和window處理的方式,也是使用error時間進行監聽.

worker.onerror = function(e){
  throw new Error(e.message + " (" + e.filename + ":" + e.lineno + ")");
};

同域限制

worker在訪問時, 只能是在同一host下才行. 即, 你的worker只能處於指定目錄下的path中。

// 這種狀況下,就沒法訪問worker
new Worker('http://crossdomain.com/worker.js');

另外, 若是你使用的是本地調試file://xxx的話, 也不能使用worker.

subworkers

在一個worker裏面能夠再spawn出其餘的worker. 使用方法和在main.js中同樣.

// 加載worker.js
var sub_worker = new Worker('subworker.js');

subworker和worker有這一樣的限制, 同域, 而且他的路由是相對於parent worker. 來看一個demo吧:

// main.js
 var worker = new Worker('worker.js');
   worker.onmessage = function (event) {
     document.getElementById('result').textContent = event.data;
   };
   
// worker.js
  // 用來進行遍歷計算
var num_workers = 10;
var items_per_worker = 1000000;

// start the workers
var result = 0;
var pending_workers = num_workers;
for (var i = 0; i < num_workers; i += 1) {
  var worker = new Worker('subworker.js');
  worker.postMessage(i * items_per_worker);
  worker.postMessage((i+1) * items_per_worker);
  worker.onmessage = storeResult;
}

// handle the results
function storeResult(event) {
  result += 1*event.data;
  pending_workers -= 1;
  if (pending_workers <= 0)
    postMessage(result); // finished!
}

// subworker.js
var start;
onmessage = getStart;
function getStart(event) {
  start = 1*event.data;
  onmessage = getEnd;
}

var end;
function getEnd(event) {
  end = 1*event.data;
  onmessage = null;
  work();
}

function work() {
  var result = 0;
  for (var i = start; i < end; i += 1) {
    // perform some complex calculation here
    result += 1;
  }
  postMessage(result);
  close();
}

另外,若是你想在當前的worker裏面加載其餘庫文件, 就可使用importScripts來導入.

// 導入其餘庫的文件
importScripts('jquery.js','react.js','react-dom.js');

worker的用處

根據worker 獨立線程這一特性. 他的使用場景也很是清晰了.反正什麼大規模數據併發,I/O操做的.均可以交給他來進行. 總的來講有一下幾種場景:

  • 懶加載數據

  • 文本分析

  • 流媒體數據處理

  • web database的更新

  • 大量JSON返回數據的處理

shared worker

除了你們所熟知的web worker, 或者更確切的來講--Dedicated workers.
總的來講web worker分爲兩種:

  • Dedicated worker (DW): 即便用 new Worker()來建立的. 該worker通常只能和creator進行通訊. 即, 在建立worker的js script中才能使用.

  • Shared Wrokers (SW): 使用new SharedWorker() 進行建立. 他能在不一樣的js script中使用.

具體來說SW和DW的區別就是一個只能在一個script中使用. 一個能夠在不一樣的script中使用.
看一個簡單demo:

// index.html 發起shared worker 通訊

 <script>
      var worker = new SharedWorker('sharedWorker.js');
      worker.port.addEventListener("message", function(e) {             console.log(e.data);
      }, false);  
      worker.port.start();  
      // post a message to the shared web worker  
      console.log("Calling the worker from script 1");
      worker.port.postMessage("script-1");
    </script>

    <script>
      console.log("Calling the worker from script 2");
      worker.port.postMessage("script-2");
    </script>

// sharedWorker.js 內
var connections = 0; 
self.addEventListener("connect", function (e) {  
    var port = e.ports[0];  
    connections++;  
    port.addEventListener("message", function (e) {  
        port.postMessage("Welcome to " + e.data +
         " (On port #" + connections + ")");  
    }, false);  
    port.start();  
}, false);

不過, SW的兼容性比較差, 能真正在實踐場景使用的地方仍是少的. 因此,這裏也只是當作瞭解.
SW 和 DW 同樣, 也有一些features:

  • 映入外部文件: importScripts()

  • 錯誤監聽: error事件監聽

  • 關閉通訊: port.close()

  • ajax交互: 有權訪問xmlHttpRequest對象

  • 能訪問navigator object

  • 訪問 location object

  • setTimeout等時間函數

相關文章
相關標籤/搜索