上一篇分享講到Javascript的單執行緒特性,以及它如何用事件佇列的方式來模擬多工。不過HTML5規格其實已經為在網頁中執行的Javascript帶來真正多執行緒的功能,這就是Web Worker。
其實不論上一篇分享或這一篇講的東西都不是定義在ECMA-262 Edition 3或即將出來的Edition 5的東西,而是網頁相關的規格。不過對於事件機制的底層實作不論ECMA-262或是DOM標準文件都沒有制定這一部份的標準,不過HTML5裡面有了!有興趣的話可以參考http://www.w3.org/TR/html5/browsers.html#event-loops
Web Worker
Worker是HTML5規格中定義的新功能,有一些參考網站:
* w3研發中標準文件-http://dev.w3.org/html5/workers/
* mozilla網站上的介紹-https://developer.mozilla.org/En/Using_DOM_workers
* mozilla網站上的參考文件-https://developer.mozilla.org/En/DOM/Worker
簡單地說,Web Worker是一個完全獨立的,執行Javascript的執行緒,主頁面與Worker之間,只透過postMessage函數與onmessage事件來溝通。postMessage用來向Worker物件傳送訊息,而Worker收到訊息時,則使用onmessage的事件處理函數來處理。發生錯誤時,則產生onerror事件。onmessage事件處理函數的第一個參數,會有一個屬性叫做data,攜帶傳送的資料。onerror事件處理函數的第一個參數則有三個屬性,message裡面是錯誤訊息,filename是worker執行的Javascript檔名,lineno則是發生錯誤的行數。另外,Worker物件還有一個方法叫做terminate(),可以強制結束其執行。下面列出相關的方法及屬性:
Worker物件
* 方法
WorkerGlobal(就是Worker的Javascript執行時的Global物件)
* 方法
目前的瀏覽器,只有Firefox3.5支援比較完整,在Worker裡還可以產生新的Worker。Chrome3以及Safari4支援Worker,但是沒辦法在Worker裡面產生Worker。
在Worker的使用上,傳遞給Worker的資料或回傳的資料,可以是數字、字串、陣列或物件,但是不能是函數。以下是一個簡單的例子,只能在Firefox3.5執行:
<script>
(function (){
with (new Worker("iron018.js")) {
onmessage = function(event) {
alert(event.data.msg);
terminate();
};
onerror = function(event) {
alert("error:"+event.message+" in "+event.filename+" line:"+event.lineno);
terminate();
};
postMessage("go");
}
})();
</script>
onmessage = function(event) {
var self = this;
worker = new Worker("iron018a.js");
worker.onmessage = function(event) {
self.postMessage(event.data);
this.terminate();
};
worker.onerror = function(event) {
self.postMessage("error:"+event.message+" in "+event.filename+" line:"+event.lineno);
this.terminate();
};
var tid = setTimeout(function(){worker.postMessage("go");clearTimeout(tid);}, 100);
}
onerror = function(event) {
postMessage("error:"+event.message+" in "+event.filename+" line:"+event.lineno);
};
(iron018.js)
onmessage = function(event) {
postMessage({
from: 'iron018a.js',
msg: 'it worked.'
});
}
onerror = function(event) {
postMessage("error:"+event.message+" in "+event.filename+" line:"+event.lineno);
};
(iron018a.js)
這個例子只是讓產生的Worker再產生一個Worker然後回傳訊息。
更複雜的例子可以參見我之前寫的文章:[Firefox 3.5 preview] web worker thread以及Safari的Web Worker速度非常搶眼
Web Worker可以讓花時間的程式在背景跑而不影響前景程式的使用,預料可以讓網頁程式的功能更加強大。另外,對網頁程式來說Web Worker是一個share nothing的分散式架構,有興趣的話可以用他來練習分散式運算,應該會很有趣。