JavaScript多線程之HTML5 Web Worker


橋和多線路電線

在博主的前些文章Promise的前世今生和妙用技巧JavaScript單線程和瀏覽器事件循環簡述中都曾提到了HTML5 Web Worker這一個概念。在JavaScript單線程和瀏覽器事件循環簡述中講述了JavaScript出於界面元素訪問安全的考慮,所以JavaScript運行時一直是被實現為單線程執行的;這也意味着我們應該盡量的避免在JavaScript中執行較長耗時的操作(如大量for循環的對象diff等)或者是長時間I/O阻塞的任務,特別是對於CPU計算密集型的操作。

例如在JavaScript中嘗試計算像fibonacci這類計算密集型的操作,就會導致整個頁面體驗被blocked。HTML5 Web Worker的出現讓我們在不阻塞當前JavaScript線程的情況下,在當前的JavaScript執行線程中可利用Worker這個類新開辟一個額外的線程來加載和運行特定的JavaScript文件,這個新的線程和JavaScript的主線程之間並不會互相影響和阻塞執行的;並且在Web Worker中提供這個新線程和JavaScript主線程之間數據交換的接口:postMessage和onmessage事件。它和C# WinForm中的BackgroundWorker很類似。

Web Worker實現fibonacci計算

利用HTML5 Web Worker實現fibonacci可像如下所示(plnkr在線demo):

fibonacci.js Worker JavaScript文件:

(function() {
  var fibonacci = function(n) {
    return n < 2 ? 1 : (fibonacci(n - 1) + fibonacci(n - 2));
  };

  onmessage = function(event) {
    postMessage({
      input: event.data,
      result: fibonacci(event.data)
    });
  };

})();

在fibonacci.js中利用onmessage方法來監聽主線程發送的fibonacci計算請求,和利用postMessage返回計算的結果到請求線程。

script.js 主線程JavaScript文件:

$(function() {
  var $input = $('#input'),
    $btn = $('#btn'),
    $result = $('#result'),
    worker = new Worker('fibonacci.js'),
    timeKey = function(val) {
      return 'fibonacci(' + val + ')';
    };

  worker.onmessage = function(event) {
    console.timeEnd(timeKey(event.data.input));
    $result.text(event.data.result);
  };

  $btn.on('click', function() {
    var val = parseInt($input.val(), 10);
    if (val) {
      console.time(timeKey(val));
      $result.text('?')
      worker.postMessage(val);
    }
  });
});

在這個JavaScript文件中,利用new Worker('fibonacci.js')方式來創建Web Worker對象,並利用Worker對象上的postMessage方法發送請求計算請求,以及利用Worker對象的onmessage的方法接受Worker線程的返回結果,並顯示在UI界面上。同時我們也利用了console最新的time API來統計計算所花費的時間。

其顯示效果如下:

html5 web worker demo

在console中打印的時間信息為:

fibonacci(10): 1.022ms
fibonacci(20): 1.384ms
fibonacci(30): 22.065ms
fibonacci(40): 1744.352ms
fibonacci(50): 202140.027ms

從這里時間輸出可以看出,在計算n為40的fibonacci 開始時間開始急速的加長,在UI中返回結果的時間也逐漸變長;但是在Web Worker后台計算的時候,它並不會阻塞我們的UI界面的其他交互。

Web Worker總結

Web Worker在這類耗時計算密集型操作中,顯得特別實用。在Web Worker中我們可以實現:

  1. 可以加載一個JS進行大量的復雜計算而不掛起主進程,並通過postMessage,onmessage進行通信;
  2. 可以在worker中通過importScripts(url)加載另外的腳本文件;
  3. 可以使用 setTimeout(),clearTimeout(),setInterval(),clearInterval();
  4. 可以使用XMLHttpRequest來發送請求,以及訪問navigator的部分屬性。

但是它也存在一些來自瀏覽器安全沙盒的限制:

  1. 不能加載跨域的JavaScript文件;
  2. 如文件開始所說,考慮到JavaScript操作DOM的安全性問題,在Web Worker中不能訪問界面中的DOM信息,對於DOM的訪問操作都必須委托給JavaScript主線程來操作;因此HTML5 Web Worker的出現的出現,並沒有改變JavaScript單線程執行的這個事實;
  3. 還有就是Web Worker的瀏覽器兼容性問題。它的瀏覽器兼容性圖如下:

html5 web worker瀏覽器兼容性

更多關於Web Worker的資料,請參考https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM