JavaScript 週報 436 期之 WebWorker 是什麼

本週 JavaScript 436期週報連接。這裏面主要我想談談 WebWorker 相關的內容。javascript

衆所周知,JavaScript 使用運行在單線程上的。可是 JavaScript 能夠處理異步代碼,其中 Ajax 就是個很好的例子。異步帶來的用戶體驗沒必要多說,可是這裏有個問題:若是異步以後的成功回調是一次密集 CPU 操做。那麼原本由於異步而產生的非阻塞用戶體驗,就又會由於沒法從事件循環出解脫而又產生阻塞。對用戶而言便又產生了不響應的 UI。這種狀況,咱們能夠認爲 JavaScript 只是解決了單線程的部分限制。能夠假設,若是咱們把這一次密集 CPU 操做也在異步中執行,那麼用戶體驗仍然一如既往地流暢。html

Web Worker 就應用而生了。前端

Web Workers 概述

Web Worker 是真正的多線程。java

Web Worker並不會阻塞事件循環。參考這個 demo 能夠看到在 5 萬條數據排序的時候,使用 WebWorker 帶來的體驗差異。Web Worker 並非 JavaScript 的一部分,它是經過 JavaScript 能夠訪問的瀏覽器特性。然而,Web Worker 並無在 Node.js 中實現,有點像子進程的概念,可是卻有不一樣。git

Web Worker是有三種類型,在 MDN 中有詳細定義:github

  • 專用 Workers
  • 共享 Workers
  • 服務 Workers

其中,專用 Workers 是經過主進程實例化,也只能經過主進程通訊;共享 Workers 能夠訪問全部同源的進程(在不一樣的瀏覽器標籤,窗口或者其餘的共享 Workers);服務 Workers 是針對源和路徑的事件驅動 worker,用在網絡不可用的狀況下,能夠控制網站和相關站點,插入和修改導航和資源請求,緩存資源等。web

如何工做

Web Workers 在瀏覽器中運行一個獨立的線程。正因如此,執行的代碼須要被包含在一個獨立的文件中,這一點比較重要。使用方式也很簡單:瀏覽器

var worker = new Worker('taks.js');
複製代碼

瀏覽器會建立一個異步下載的文件線程。當下載完成後,會被執行。經過調用 postMessage 方法來使用建立好的 worker。它可讓一個 Web Worker 和頁面之間通訊。緩存

如何使用 postMessage 方法

比較新的瀏覽器支持 JSON 做爲第一個參數,而舊的瀏覽器只支持字符串。安全

<button onclick="startComputation()">Start computation</button>

<script> function startComputation() { worker.postMessage({'cmd': 'average', 'data': [1, 2, 3, 4]}); } var worker = new Worker('doWork.js'); worker.addEventListener('message', function(e) { console.log(e.data); }, false); </script>
複製代碼

在 new 一個 Worker 以後,給它的實例註冊一個叫 message 的監聽事件。同時在咱們的 doWork.js 裏,也要註冊相同事件用來處理數據。

self.addEventListener('message', function(e) {
  var data = e.data;
  switch (data.cmd) {
    case 'average':
      var result = calculateAverage(data); // Some function that calculates the average from the numeric array.
      self.postMessage(result);
      break;
    default:
      self.postMessage('Unknown command');
  }
}, false);
複製代碼

當消息到達的時候,worker 就開始執行計算,具體來講運行 calulateAverage 方法。結束以後,把結果傳遞給主頁面。在 worker 的上下文環境中,selfthis 都是 worker 的全局,與 window 無關。有兩種方式能夠結束 worker: worker.terminate()self.close()

Web Worker 可用特性

  • navigator 對象
  • location 對象(只讀)
  • XMLHttpRequest
  • setTimeout()/clearTimeout()setInterval()/clearInterval()
  • 應用緩存
  • 使用 importScripts() 導入外部腳本
  • 建立其餘的 web workers

Web Worker 限制

  • DOM(很顯然,多線程的操做DOM是不合理和不安全的)
  • window 對象
  • document 對象
  • parent 對象

幾個 Web Workers 的場景

  • 光線追蹤

    爲了模擬光線路徑,這種場景是須要大量計算的,可是不能再每次大量計算的時候就讓光線變得卡頓或者不天然,這時候workers 就能夠發揮做用了。

  • 加密

    也是純粹的計算工做,交給 web workers 正當其用。並且有些加密解密的操做是至關消耗時間的。

  • 預加載數據 當網絡不是很穩定的時候,能夠先把數據取出來存在本地瀏覽器緩存中,這樣在須要的時候就會減小延遲感

  • 拼寫檢查

    若是對應的檢查數據是一本字典的話。這種場景下,使用 web worker 就十分必要了。

總結一下使用 Web Workers 的場景的共同點:

  1. 延遲甚至不須要 DOM 操做的狀況
  2. 短期使用產生大量計算,會阻塞 UI 線程,致使卡頓的場景
  3. 預處理,異步處理的部分場景

小結

Web Worker 是個瀏覽器實現的特性,儘管如此,咱們仍是可以在某些地方發揮它的優點去加強用戶體驗,遵循「漸進加強,平穩退化」得原則。沒有理由去拒絕使用它。但其實,Web Worker 的使用場景也十分具備特色,它應該不是做爲解決卡頓問題的首選,由於在前端,除了動畫之外每每沒有特別大的計算量。大多數的不流暢用戶體驗,多半是重繪和重排沒有優化好而引發的,千萬不可緣木求魚,爲了 Web Worker 什麼都往上鼓搗。

參考資料

  1. blog.sessionstack.com/how-javascr…

pic
相關文章
相關標籤/搜索