Menu

用 Web Workers 提升前端 JavaScript 處理性能


你有沒有想過在運行大型複雜的JavaScript腳本的時候不會發生瀏覽器假死

你有沒有想過JavaScript可以在後台運行?

你有沒有想過JavaScript函數甚至可以在多個進程中同時運行?


不可能?當你看完本文,也許會讓你感覺很興奮!

 

什麼是Web Workers

Web Workers為WEB前端網頁上的腳本提供了一種能在後台進程中運行的方法。一旦它被創建,Web Workers就可以通過postMessage()向任務池發送任務請求,執行完之後再通過postMessage()返回消息給創建者指定的事件處理程序(通過onmessage進行捕獲)。


Web Workers進程能夠在不影響用戶界面的情況下處理任務,並且,它還可以使用XMLHttpRequest來處理I/O,無論responseXML和channel屬性是否為null。

注意:通常,後台進程(包括web workers進程)不能對DOM進行操作。如果希望後台程序處理的結果能夠改變DOM,只能通過返回消息給創建者的回調函數進行處理。



瀏覽器支持:

FireFox3.5(Firefox 3.1 support for DOM workers)
Safari4
支持html5的瀏覽器

 

進程安全

Workers接口可以創建真正的系統級別的進程,如果你不小心的話,你的代碼很容易引起並發操作效果,這將會很有趣。


在Mozilla下,Workser並發操作常發生在:

1、在做網站下載的時候使用Worker。

2、使用Worker實現處理擴展功能。


創建一個Worker

我們可以很簡單地創建一個worker,只要調用Worker(URI)構造函數即可。參數URI,要執行的腳本文件地址。
如果你想獲取worker進程的返回值,可以通過它的onmessage屬性來綁定一個事件處理程序,如:

myWorker.onmessage = function(event){
alert('Called back by the worker!');
};

 


第一行用來創建和運行worker進程,第二行設置worker的onmessage屬性用來綁定指定的事件處理程序,當worker私有的postMessage()方法被調用時,這個被綁定的程序就會被觸發。

 

創建一個subworkers

如果原意,你可以創建多個workers。subworkers必須寄宿於同一個父頁面下,並且,它的URI必須與parent worker的地址同源。這樣可以很好的維持它們的依賴關係。

 

Timeouts 和 intervals

Workers可以使用timeouts和intervals。這很有用,例如,如果你想讓你的worker進程週期性地運行而不是不停的循環下去的話,你就可以使用了。

參見:setTimeout(),clearTimeout(),setInterval(),clearInterval()



終止 worker

如果你需要馬上終止一個正在運行中的worker,你可以調用它的terminate()方法:

myWorker.terminate();

這樣,一個worker進程就被結束了。

 

錯誤捕獲 Handling errors

當worker發生運行時錯誤時,它的onerror事件就會被觸發。該事件接收一個error的事件,該事件不會冒泡,並且可以取消。要取消該事件可以使用preventDefault()方法。

此錯誤事件有3個屬性:

  • message:可讀的錯誤信息
  • filename:發生錯誤的腳本文件名稱
  • lineno:發生錯誤的腳本所在文件的行數


訪問navigator對象

Workers可以訪問navigator對象,它包含下面可以用來標示瀏覽器的字符:

  • appName
  • appVersion
  • platform
  • userAgent

 

導入腳本和庫

Worker進程可以訪問全局函數importScripts(),該方法可以將腳本或庫導入到它們的作用域中。

此方法可以接受空的參數或多個腳本URI參數,下面這些形式都是合法的:

importScripts();/* imports nothing */
importScripts('foo.js');/* import just "foo.js" */
importScripts('foo.js','bar.js');/* imports two scripts */

 


Firefox會加載列出的每一個腳本文件,然後運行並初始化。這些腳本中的任何全局對象都可以被worker使用。


注意:腳本下載可能順序不一樣,但,執行的順序一定是按importScripts中列出的順序進行,而且是同步的,在所有腳本加載完並運行結束後importScripts才會返回。

 

演示

這部分,我們將演示如何使用DOM Workers.

 


在後台執行指令

Workers的一個很有用的方法就是使得你的代碼可以在後台運行,而不影響用戶界面。下面,我們來演示一下使用worker進行Fibonacci數列的計算。

JavaScript代碼:

下面的Javascript代碼保存到 fibonacci.js 文件


var results = [];

var resultReceiver = function(event){
results.push(parseInt(event.data,10));
if(results.length==2){
postMessage(results[0]+results[1]);
}
};

var errorReceiver = function(event){
throw event.data;
};

var onmessage = function(event){
var n = parseInt(event.data,10);
if(n==0||n==1){
postMessage(n);
return;
}
for(var i=0;i<=2;i++){
var worker = new Worker("fibonacci.js");
worker.onmessage = resultReceiver;
worker.onerror = errorReceiver;
worker.postMessage(n-i);
}
};

 


 

onmessage函數在worker調用postMessage()時被觸發,這時便開始遞歸。在裡邊創建新的worker拷貝對每次的計算結果進行迭代。

HTML代碼


<!DOCTYPE HTML PUBLIC "-//W3C/DTD HTML4.0 Transitional//EN">
<html>
<head>
<title>Test threads fibonacci</title>
</head>
<body>
<div id="result">http://www.v-ec.com/dh20156/article.asp?id=242</div>
<script type="text/javascript">
var worker = new Worker("fibonacci.js");
worker.onmessage = function(event){
document.getElementById('result').innerHTML = event.data;
dump('Got:'+event.data+'\n');
};
worker.onerror = function(event){
dump('Worker error:'+error.message+'\n');
throw error;
};
worker.postMessage('5');
</script>
</body>
</html>

 



在頁面中創建了一個ID為result的DIV用來顯示計算結果,然後創建worker,設置onmessage事件用來顯示計算結果到result,設置onerrer事件用來設置dump錯誤信息。
最後,發送“5”到worker,開始計算。

 

在後台操作 WEB I/O

你可以在此查看到一篇關於Using workers in extensions的文章。

 

在多個workers進程中處理任務

隨著多核計算機的普及,在多進程處理複雜的任務也越來越被更多的人使用,在多個workers進程中處理任務的演示不久將會提供給大家。

 

在workers中創建workers

前面Fibonacci例子的演示中我們看到,在workers中可以創建其他的workers,這使得遞歸很容易進行。

 

發送對象給workers

你可以通過postMessage()方法安全地將對象傳遞到workers或者從中返回對象;這些對象將被自動轉換為JSON格式。

var onmessage = function(e){
postMessage(e.data);
};

注意:在workers中進出的對象不能包含函數和循環引用,因為JSON不支持它們。

 

See also參見:

WebWorkers

Worker

WorkerGlobalScope

SharedWorker

Web Workers specification

 轉載請註明出處:http://www.v-ec.com/dh20156/article.asp?id=242

經過WEB前端DHTML精英俱樂部測試發現,Safari4已經可以支持Web Workers,不過貌似還不支持在worker中創建worker,所以,本文中上面的Fibonacci例子測試失敗,WEB前端DHTML精英俱樂部重新寫了一個實例進行演示:

WEB前端專家DHTML精英俱樂部對Web Workers進行的性能測試!