之前咱們總說,JS是單線程沒有多線程,當JS在頁面中運行長耗時同步任務的時候就會致使頁面假死影響用戶體驗,從而須要設置把任務放在任務隊列中;執行任務隊列中的任務也並不是多線程進行的,然而如今HTML5提供了咱們前端開發這樣的能力 - Web Workers API,咱們一塊兒來看一看 Web Worker 是什麼,怎麼去使用它,在實際生產中如何去用它來進行產出。前端
Web Workers 使得一個Web應用程序能夠在與主執行線程分離的後臺線程中運行一個腳本操做。這樣作的好處是能夠在一個單獨的線程中執行費時的處理任務,從而容許主(一般是UI)線程運行而不被阻塞。ajax
它的做用就是給JS創造多線程運行環境,容許主線程建立worker線程,分配任務給後者,主線程運行的同時worker線程也在運行,相互不干擾,在worker線程運行結束後把結果返回給主線程。這樣作的好處是主線程能夠把計算密集型或高延遲的任務交給worker線程執行,這樣主線程就會變得輕鬆,不會被阻塞或拖慢。這並不意味着JS語言自己支持了多線程能力,而是瀏覽器做爲宿主環境提供了JS一個多線程運行的環境。算法
不過由於worker一旦新建,就會一直運行,不會被主線程的活動打斷,這樣有利於隨時響應主線程的通性,可是也會形成資源的浪費,因此不該過分使用,用完注意關閉。或者說:若是worker無實例引用,該worker空閒後當即會被關閉;若是worker實列引用不爲0,該worker空閒也不會被關閉。canvas
看一看它的兼容性api
Browser IE Edge FireFox Chrome Safari
version 10+ 12+ 3.5+ 4+ 4+瀏覽器
2.1 限制安全
worker線程的使用有一些注意點網絡
同源限制 worker線程執行的腳本文件必須和主線程的腳本文件同源,這是固然的了,總不能容許worker線程到別人電腦上處處讀文件吧
文件限制 爲了安全,worker線程沒法讀取本地文件,它所加載的腳本必須來自網絡,且須要與主線程的腳本同源
DOM操做限制 worker線程在與主線程的window不一樣的另外一個全局上下文中運行,其中沒法讀取主線程所在網頁的DOM對象,也不能獲取 document、 window等對象,可是能夠獲取 navigator、 location(只讀)、XMLHttpRequest、 setTimeout族等瀏覽器API。
通訊限制 worker線程與主線程不在同一個上下文,不能直接通訊,須要經過 postMessage方法來通訊。
腳本限制 worker線程不能執行 alert、 confirm,但可使用 XMLHttpRequest 對象發出ajax請求。
2.2 例子多線程
在主線程中生成 Worker 線程很容易:異步
Worker()構造函數,第一個參數是腳本的網址(必須遵照同源政策),該參數是必需的,且只能加載 JS 腳本,不然報錯。第二個參數是配置對象,該對象可選。它的一個做用就是指定 Worker 的名稱,用來區分多個 Worker 線程。
// 主線程
關於api什麼的,直接上例子大概就能明白了,首先是worker線程的js文件:
在HTML文件中的body中:
能夠本身運行一下看看效果,上面用到了一些經常使用的api
主線程中的api, worker表示是 Worker 的實例:
worker.postMessage: 主線程往worker線程發消息,消息能夠是任意類型數據,包括二進制數據
worker.terminate: 主線程關閉worker線程
worker.onmessage: 指定worker線程發消息時的回調,也能夠經過worker.addEventListener('message',cb)的方式
worker.onerror: 指定worker線程發生錯誤時的回調,也能夠worker.addEventListener('error',cb)
Worker線程中全局對象爲 self,表明子線程自身,這時 this指向 self,其上有一些api:
我的以爲,Web Worker咱們能夠當作計算器來用,須要用的時候掏出來摁一摁,不用的時候必定要收起來~
加密數據
有些加解密的算法比較複雜,或者在加解密不少數據的時候,這會很是耗費計算資源,致使UI線程無響應,所以這是使用Web Worker的好時機,使用Worker線程可讓用戶更加無縫的操做UI。
預取數據
有時候爲了提高數據加載速度,能夠提早使用Worker線程獲取數據,由於Worker線程是能夠是用 XMLHttpRequest 的。
預渲染
在某些渲染場景下,好比渲染複雜的canvas的時候須要計算的效果好比反射、折射、光影、材料等,這些計算的邏輯可使用Worker線程來執行,也可使用多個Worker線程,這裏有個射線追蹤的示例。
複雜數據處理場景
某些檢索、排序、過濾、分析會很是耗費時間,這時可使用Web Worker來進行,不佔用主線程。
預加載圖片
有時候一個頁面有不少圖片,或者有幾個很大的圖片的時候,若是業務限制不考慮懶加載,也可使用Web Worker來加載圖片,能夠參考一下這篇文章的探索,這裏簡單提要一下。
在 Web Workers 實戰的時候注意:
雖然使用worker線程不會佔用主線程,可是啓動worker會比較耗費資源
主線程中使用XMLHttpRequest在請求過程當中瀏覽器另開了一個異步http請求線程,可是交互過程當中仍是要消耗主線程資源
在 Webpack 項目裏面使用 Web Worker 請參照:怎麼在 ES6+Webpack 下使用 Web Worker
至於還有Shared Worker、Service Worker 什麼的,咱們就不看了,IE不喜歡
網上的帖子大多深淺不一,甚至有些先後矛盾,在下的文章都是學習過程當中的總結,若是發現錯誤,歡迎留言指出~