初始WebWorker

基本概念

JS單線程:咱們都知道JavaScript它是一個單線程的語言,同一時間只能作一件事。好比:在瀏覽器中,某一時刻咱們在操做DOM,大家這個時刻咱們就不能去運行JavaScript代碼,反過來也是,當咱們在運行JavaScript代碼的時候,咱們也不能去操做DOM,這個也就是JS的單線程。爲何要JS成單線程?由於在瀏覽器環境下,若是是多線程的,也就是操做DOM和運行JavaScript代碼是並行處理的話,假如某個時刻,瀏覽器正在繪製DOM,可是這個時候的JavaScript代碼改變了DOM,這樣就會形成一個不一致,所以JS就被設計成了一門單線程語言。node

雖然JS是單線程,可是它的宿主,咱們的瀏覽器環境(node環境)它是一個多線程的,在瀏覽器和node裏面只有一條JS線程,可是還有不少其餘的線程。以瀏覽器爲例,瀏覽器的常駐線程(以下)大概有前三個:第一個,UI線程,也就是DOM瀏覽器元素的迴流和重繪,這個UI線程與JavaScript線程是互斥的。第二個就是JavaScript線程,單線程的運行JS代碼。第三個是GUI線程,它主要是處理與用戶交互的一些邏輯,好比點擊某一個元素,拖動了或者縮放了這個就是由GUI線程處理的。除此以外還有NetWorker線程,網絡線程,發送ajax請求,發送http請求都是走的network線程。還有File線程,讀取文件。還有一個定時器線程。web

  • UI線程 - 迴流和重繪 - 與Javascript線程互斥
  • JavaScript線程 - 單線程運行JavaScript
  • GUI線程 - 交互線程
  • Network線程
  • File線程
  • 定時器線程

這裏可能會有一個問題是ajax請求對於JS來講是異步的,可是JavaScript是單線程的,這樣就涉及到了一個基於事件的驅動。當咱們發起一個網絡請求時,瀏覽器會把這一部分網絡請求交給network線程去處理,而後JavaScript線程等待network的指令驅動。在沒有代碼要運行的狀況下,JavaScript線程始終是空閒的,有了事件驅動以後,它會一直處於一個輪詢的狀態(Event Loop),瀏覽器會不斷查詢目前是否有JavaScript線程須要運行,若是有就運行,沒有就保持閒置。當一個網絡請求發送出去,這個時候的JavaScript線程是處於閒置的,可是瀏覽器仍是會不停的詢問,當network線程結束後,瀏覽器發現有新的JavaScript代碼須要執行,它就會驅動JavaScript的線程去處理網絡請求返回的結果,這個就是JS 基於事件驅動的模型。ajax

Event Loop(事件輪詢圖)瀏覽器

圖片描述

異步是將耗時比較長的任務放置到Event Queue 事件隊列的尾部。安全

WebWorker

WebWorker爲了解決瀏覽器假死這個問題而孕育而生的一項新技術。它是多線程模型,也是基於宿主。它屬於JavaScript線程中的一個子線程,它徹底受主線程控制,可是在WebWorker裏面是不能操做DOM的。由於上面提到的UI線程和JavaScript線程是互斥的,這個互斥也就保證了DOM的惟一性,所以主的基調不能改變,可是須要有一個新的線程來分擔繁雜的計算任務,這個也就是WebWorker。網絡

瀏覽器的兼容性

圖片描述

應用場景

WebWorker是爲了處理影響UI線程的JavaScript運算。由於在同一時刻,UI線程和JavaScript線程只能有一個在運行,若是這個時候JS的線程承擔過多運算的話,它的耗時就變得很長,這個時候的UI線程是沒有反應的,這樣就形成了頁面的假死。多線程

WebWorker特色

  • 一旦新建就會始終運行,不會被主線程打斷。即便主線程卡死了,WebWorker依然在運行。
  • 同源限制,對於同一個WebWorker來說,只有同源的網頁纔可以訪問。
  • 不能操做和訪問DOM(window、document),由於要保證DOM 的惟一性。
  • 不能使用包含交互的全局方法(alert、confirm),可是可使用XMLHttpRequest、setTimeout、setInterval
  • 不能讀取本地文件(不止WebWorker不能讀取,JavaScript主線程也不能讀取),出於安全性的考慮,瀏覽器是不容許js讀取本地文件的。
  • WebWorker分爲兩個:dedicated web worker(專用線程) ,只有一個網址一個頁面可使用這個線程和 shared web worker(共享線程),多個同源的網頁能夠共享一個WebWorker,這樣爲跨頁面通訊提供了一種可能。

基本用法

  • 建立WebWorker異步

    const webWorker = new Worker('main.js');
    let result = 0;
    const fibonacci = (n) => {
          if (n <= 1) return 1;
          return fibonacci(n - 1) + fibonacci(n - 2);
    }
    
    result = fibonacci(10);
    console.log('result', result);
  • 向WebWorker發送消息(數據)oop

    webWorker.postMessage({ number : 10 });
  • WebWorker接收消息post

    webWorker.addEventListener('message', event => {
          console.log('received webworker data', event.data);
    }, false);
  • WebWorker發送消息(返回數據)

    this.postMessage(returnValue);
  • 主線程接收WebWorker消息

    webWorker.addEventListener('message', event => {
          console.log('received webworker data', event.data);
    }, false);
  • 關閉WebWorker

    方式一:在主線程關閉WebWorker
    webWorker.terminate();
    
    方式二:在子線程,WebWorker內部本身調用本身的close方法,再也不接收新的 Macrotask(宏任務)
    this.close();

WebWorker調用腳本

importScripts('./one.js', './two.js');

WebWorker錯誤監聽

webWorker.addEventListener('error', error => {
    console.error(error.filename, error.lineno, error.message);
});
相關文章
相關標籤/搜索