在【異步發展史,此次必定會!】中,由於js引擎是單線程的,因此咱們須要異步編程,須要將耗時的操做異步處理。可是當這些執行異步任務時,它們先被放入瀏覽器的事件任務隊列中去,等到執行棧空閒時纔會按照隊列先進先出的原則被一一執行,但終究仍是單線程。如果複雜耗時的任務仍然會耗費較大的時間。html
爲了能使js引擎多線程,webworker應運而生,固然,js自己仍然是單線程,可是js運行的環境瀏覽器爲其提供多線程。git
官方文檔github
經過使用Web Workers,Web應用程序能夠在獨立於主線程的後臺線程中,運行一個腳本操做。這樣作的好處是能夠在獨立線程中執行費時的處理任務,從而容許主線程(一般是UI線程)不會所以被阻塞放慢。web
Worker 線程新建後,就會長時間運行chrome
不會被主線程上的活動(好比用戶點擊按鈕、提交表單)打斷編程
有利於隨時響應主線程的通訊,並同時保證頁面對用戶的及時響應。canvas
Worker 比較耗費資源,不該該過分使用,使用完畢,請當即關閉。segmentfault
分配給 Worker 線程運行的腳本文件,必須與主線程的腳本文件同源。跨域
Worker 線程所在的全局對象,與主線程不同,沒法讀取主線程所在網頁的 DOM 對象,也沒法使用document、window、parent這些對象。可是,Worker 線程能夠navigator對象和location對象。瀏覽器
Worker 線程和主線程不在同一個上下文環境,它們不能直接通訊,必須經過消息完成。
Worker 線程不能執行alert()方法和confirm()方法,但可使用 XMLHttpRequest 對象發出 AJAX 請求。
Worker 線程沒法讀取本地文件,即不能打開本機的文件系統(file://),它所加載的腳本,必須來自網絡。
//形如const myWorker = new Worker(aURL, options); aURL:js文件名 [options]一些屬性
let myWorker = new Worker("worker.js");
//在chrome中不容許讀取本地文件,因此最好起一個本地服務器讀取或者是讀取同源網絡文件
複製代碼
onmessage: 監聽事件
postmessage: 傳送事件
主線程文件
//當觸發耗時事件時
first.onchange = function() {
myWorker.postMessage([first.value,second.value]);
console.log('Message posted to worker');
}
second.onchange = function() {
myWorker.postMessage([first.value,second.value]);
console.log('Message posted to worker');
}
複製代碼
worker.js
self.onmessage = function(event){
console.log('Worker recieved message');
};
複製代碼
主線程文件
myWorker.terminate();
複製代碼
子線程文件
self.close();
複製代碼
主線程能夠監聽 Worker 是否發生錯誤。若是發生錯誤,Worker 會觸發主線程的error事件
//方一:
myWorker.onerror(function (event) {
});
//方二:
myWorker.addEventListener('error', function (event) {
});
複製代碼
Worker 內部若是要加載其餘腳本,有一個專門的方法importScripts()
importScripts(); /* imports nothing */
importScripts('foo.js'); /* imports just "foo.js" */
importScripts('foo.js', 'bar.js'); /* imports two scripts */
importScripts('//example.com/hello.js'); /* You can import scripts from other origins */
複製代碼
主線程與worker之間的通訊是一種值拷貝的過程,便是傳值而不是傳址。其實是先將數據JSON.stringify以後再JSON.parse。以這種拷貝的方式會形成性能問題。好比,主線程向 Worker 發送一個 500MB 文件,默認狀況下瀏覽器會生成一個原文件的拷貝。爲了解決這個問題,JavaScript 容許主線程把二進制數據直接轉移給子線程,可是一旦轉移,主線程就沒法再使用這些二進制數據了,這是爲了防止出現多個線程同時修改數據的麻煩局面。這種轉移數據的方法,叫作Transferable Objects。這使得主線程能夠快速把數據交給 Worker,對於影像處理、聲音處理、3D 運算等就很是方便了,不會產生性能負擔。
var transfer = new ArrayBuffer(1);
worker.postMessage(transfer, [transfer]);
複製代碼
經過使用從<canvas>
或者<video>
元素中獲取的數據,能夠把圖像分割成幾個不一樣的區域而且把它們推送給並行的不一樣Workers來作計算
因爲在使用Web Worker的時候,咱們有更多潛在的CPU可用時間,咱們如今能夠考慮一下JavaScript中的新應用場景。例如,咱們能夠想像在不影響UI體驗的狀況下實時處理用戶輸入。利用這樣一種可能,咱們能夠想像一個像Word(Office Web Apps 套裝)同樣的應用:當用戶打字時後臺在詞典中進行查找,幫助用戶自動糾錯等等
git 地址
注意:要用http-server形式開啓才能打開文件
官方文檔
阮一峯老師的博客
聊聊Webworker ⬅️這位寫的超棒 還有在線demo 建議全文細讀