我們都知道客戶端JAVAScript有一個基本的特性就是單線程。這是有一定歷史原因的,暫且不深究。隨著web應用的越來越復雜,客戶端的js可能會承擔越來越繁重的計算任務,從而導致UI線程被阻塞無法及時響應用戶的操作。
worker的出現,就是來解放主線程的js的計算任務的,由于安全的考慮,worker也會受到一定的限制。
1. 基本知識
在Web Worker標準中,定義了解決客戶端JavaScript無法多線程的問題。
- worker是指執行代碼的并行線程。
- Web Workers處在一個自包含的執行環境,無法訪問Window對象和Document對象,
- 和主線程之間的通信也只能通過異步消息傳遞機制來實現。
- 提供一種使用異步API的方式,同時運行書寫需要長時間運行的函數而不會帶來循環事件和導致瀏覽器崩潰的問題。
- Web Workers標準中,有兩部分組成Worker對象和WorkerGlobalScope全局對象。
2. Worker對象
- 使用構造函數Worker()創建Worker對象
var loader = new Worker(url)
- url:可以采用相對路徑和絕對路徑,但是采用絕對路徑必須和包含該腳本的文檔是同源的。
- 使用postMessage()傳遞參數給Worker
- 傳遞給postMessage()方法的值hi賦值,最終的副本會通過message事件傳遞給Worker
loader.postMessage('file.txt');
- 通過message事件來接收Work的響應消息
worker.onmessage = function(e){ var message = e.data; console.log('URL contents: ' + message); }
- 使用terminate()終止Worker
worker.onmessage = function(e){ //接收處理Worker的響應消息 //終止worker worker.terminate(); }
此外,Worker可以通過error事件來處理異常。
worker.onerror = function(e){ concole.log('Error at ' + e.filename + ':' + e.lineno + ':' + e.message); }
和所有事件目標一樣,Worker對象也定義了標準的addEventListener()和removeEventListener()
3. WorkerGlobalScope全局對象
在通過Worker()構造函數創建一個新Worker的時候,指定了包含JavaScript代碼文件的URL。該代碼會運行在一個全新的JavaScript運行環境中,完全和創建Worker的腳本隔離開來。
WorkerGlobalScope全局對象表示了該新的運行環境,它是新創建的Worker的全局對象。
3.1 與外部Worker的通信
1. postMessage() & message事件
WorkerGlobalScope對象同樣有postMessage()方法和message事件,利用這兩者可以與外部Worker進行通信
//worker內部 onmessage = function(e){ postMessage(e.data); }
2. close()
同樣,Worker可以使用close()來關閉自己,但是要注意的是,Worker對象上沒有定義任何API用于檢測Worker是否已關閉。因此,如果一個Worker要使用close()方法將自己關閉,那么最好是先傳遞”關閉”的信息。
3. importScripts()
Worker內部使用此方法來加載任何需要的庫代碼。而是此方法是一個同步的方法,它在直到所有的腳本都已經載入并運行完成才會返回。
//在開始工作前,現在如需要的類、工具函數 importScript('collections/Set.js','utils/base64.js');
3.2 WorkerGlobalScope的屬性
它擁有所有核心JavaScript全局對象擁有的屬性,同時,還擁有部分客戶端Window對象的一些屬性。
- self:對全局對象自身的引用
- 計數器方法:setTimeout()/clearTimeout()/setInterval()/clearInterval()
- location:只讀
- navigator
- 常用的事件目標方法:addEventListener()和removeEventListener()
- onerror屬性
4. 應用場景:腳本化HTTP請求
WorkerGlobalScope對象好包含一些重要的構造函數,其中就有XMLHttpRequest(),以便Worker可以通過它進行腳本化的HTTP請求。
在Worker中發起同步的XmlHttpRequest
//Worker內部 onmessage = function(e){ var urls = e.data; //要獲取的url var contents = []; //url指定的內容 var i,len,url; for(i = 0, len = urls.length; i < len; i++){ var url = urls[i]; var xhr = new XMLHttpRequest(); xhr.open('GET',url,false);//false表示進行同步請求 xhr.send(); if(xhr.status !== 200){ throw Error(xhr.status + ' ' + xhr.statusText + ': ' + url); } contents.push(xhr.responseText); } //返回url的內容 postMessage(contents); }