Web Worker API

簡介

  Web Worker能夠理解爲js在後臺線程中運行的方法,它能夠執行js代碼而不阻塞用戶UI界面。一個Web Worker能夠將消息發送到建立它的JavaScript代碼(只要運行在同源的父頁面中,workers能夠依次生成新的workers), 反之也能夠從主線程接收消息
  注意:worker運行在另外一個全局上下文中,不一樣於當前的window。所以,使用window快捷方式獲取當前全局的範圍,在一個Worker內將返回錯誤(直接訪問你須要訪問的屬性便可!如:console而不是window.console)。跨域

worker中可用函數和接口

在WebWorker中有些方法和屬性是不能被訪問的,好比BOM的一些API和DOM相關的一些API,localStorage,SessionStorage等,可是大部分的window對象是能夠被訪問的好比:Websocket,XMLHttpRequest(一樣不能跨域☹)Console Api,Array,Date,Math,String等等,就是說涉及到頁面操做和頁面中的對象通通不能被訪問,它的應用場景是替代主線程執行須要消耗頁面性能的代碼。這裏有一份關於WebWorker容許訪問的方法及屬性清單瀏覽器

主要wroker類型

經常使用worker爲專用worker(僅在單一腳本中被使用)和共享worker(以同時被多個腳本使用);DedicatedWorkerGlobalScope和SharedWorkerGlobalScope對象分別表明它們的上下文socket

使用

爲了更好的錯誤處理控制及向下兼容須要作些兼容檢測函數

if (window.Worker) {
    some codes ...
}

生成Worker

調用Worker()構造函數建立一個Worker對象,該對象接收指定的URL腳本(腳本必須遵照同源策略不然將拋出錯誤)post

var myWorker = new Worker('worker.js');

數據傳遞

  主線程和worker線程都使用postMessage()方法發送各自的消息,使用onmessage事件處理函數來響應消息(消息被包含在Message事件的data屬性中),這個過程當中數據並非被共享而是被複制。在主線程中使用時,onmessage和postMessage() 必須掛在worker對象上,而在worker中使用時不用這樣作。緣由是,在worker內部,worker是有效的全局做用域。性能

/*主線程*/
//發送數據至worker
myWorker.postMessage('can you hear me?');
//從worker線程監聽接收數據
myWorker.onmessage = function(e) {
    console.log(e.data);//'I can hear you!'
}

/*worker線程*/
//從主線程監聽接收數據
onmessage = function(e) {
    console.log(e.data);//'can you hear me?'
    //發送數據至worker
    e.data && postMessage('I can hear you!');
}

終止worker

若是你須要從主線程中馬上終止一個運行中的worker,能夠調用worker的terminate方法:線程

myWorker.terminate();//worker 線程會被當即殺死

在worker線程中,workers 也能夠調用本身的close方法進行關閉:code

close();

錯誤處理

當worker出現運行中錯誤時,它的onerror事件處理函數會被調用。它會收到一個擴展了 ErrorEvent 接口的名爲 error的事件。該事件不會冒泡而且能夠被取消;爲防止觸發默認動做,worker能夠調用錯誤事件的preventDefault()方法。對象

錯誤事件有如下三個核心的字段:
message
可讀性良好的錯誤消息。
filename
發生錯誤的腳本文件名。
lineno
發生錯誤時所在腳本文件的行號。接口

生成子worker

若是須要worker可以生成更多的worker。即subworker,但必須託管在同源的父頁面內。注意:subworker解析 URI時會相對於父worker的地址而不是自身頁面的地址。這使得worker更容易記錄它們之間的依賴關係。

引入腳本與庫

Worker 線程可以訪問一個全局函數importScripts()來引入腳本,該函數接受0個或者多個URI做爲參數來引入資源;如下例子都是合法的:

importScripts();//什麼都不引入
importScripts('foo.js');//只引入"foo.js
importScripts('foo.js', 'bar.js');//引入兩個腳本

注意: 腳本的下載順序不固定,但執行時會按照傳入 importScripts() 中的文件名順序進行。這個過程是同步完成的;直到全部腳本都下載並運行完畢, importScripts() 纔會返回。

關於共享worker

一個共享worker能夠被多個腳本使用——即便這些腳本正在被不一樣的window、iframe或者worker訪問。

生成共享worker

var myWorker = new SharedWorker('worker.js');//和專用worker不一樣構造器爲SharedWorker

數據傳遞

和專用worker不一樣的是與一個共享worker通訊必須經過端口對象即一個確切的打開的端口供腳本與worker通訊(在專用worker中這一部分是隱式進行的)。

在傳遞消息以前,端口鏈接必須被顯式的打開,打開方式是使用onmessage事件處理函數或者start()方法:

//方式1
myWorker.port.onmessage = function(e) {
    ...
}
//方式2(只在一種狀況下須要,那就是消息事件被addEventListener()方法使用。)
myWorker.port.start();
myWorker.port.addEventListener('message',function(e){
    ...
})

而後就能夠像以前那樣發送和接收消息了,可是postMessage()方法必須被端口對象調用:

/*主線程*/
myWorker.port.postMessage('I posted some message!');//發送
myWorker.port.onmessage = function(e) {//監聽接收
    ...
}

/*worker線程*/
onconnect = function(e) {
    var port = e.ports[0];
    port.onmessage = function(e) {
        var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
        port.postMessage(workerResult);
    }
}

在worker線程中須要注意的是:當一個端口鏈接被建立時(例如:在父級線程中,設置onmessage事件處理函數,或者顯式調用start()方法時),使用onconnect事件處理函數來執行代碼。諸如postMessage()和onmessage也必須在端口鏈接上訪問。

瀏覽器兼容

Desktop

特性 Chrome Firefox (Gecko) Internet Explorer Opera Safari (WebKit)
基礎支持 4 3.5 (1.9.1) 10.0 10.6 4
共享worker 4 29 未實現 10.6 6.1

Mobile

特性 Android Chrome for Android Firefox Mobile (Gecko) Firefox OS (Gecko) IE Phone Opera Mobile Safari Mobile
基礎支持 4.4 4 3.5 1.0.1 10.0 11.5 5.1
共享worker 未實現 4 8 1.0.1 未實現 未實現 未實現
相關文章
相關標籤/搜索