Html5 Web Worker API 已推出幾年,最近半年來有多次在國外社群被討論到,不論是穩定度還是安全性,加上最近一年mobile web開發盛行,因此想來撰寫一篇來談談目前web worker在mobile web上使用心得。
Html5 Web Worker API 已推出幾年,最近半年來有多次在國外社群被討論到,不論是穩定度還是安全性,加上最近一年mobile web開發盛行,因此想來撰寫一篇來談談目前web worker在mobile web上使用心得。
首先,我們想說明為何要使用web worker?
一般Browser在處理javascript時(先不談異步部分),必須是一段處理完再處理下一段,這樣會遇到一個問題:若有一段程式執行過久,則其他段程式想執行必須要等待這端程式處理完,才可以開始進行。
然而webworker就是在瀏覽器中創造另一個通道,可以把執行過久的那段程式獨立在這個通道執行,並且讓這個通道與原來的通道可以同時並行處理。
目前網路上有幾個實用的Demo,我這邊向大家展示一個最能表達出web worker特色的例子,請看:
http://slides.html5rocks.com/#web-workers
也許有人會問,何種方式會導致程式執行過久?
最主要常見的在於data的傳遞與處理,來看看國外專家的整理如下:
• Encoding/decoding a large string
• Complex mathematical calculations (e.g., prime numbers, encryption, simulated
annealing, etc.)
• Sorting a large array
• Network requests and resulting data processing
• Calculations and data manipulation on local storage
• Prefetching and/or caching data
• Code syntax highlighting or other real-time text analysis (e.g., spell checking)
• Image manipulation
• Analyzing or processing video or audio data (including face and voice recognition)
• Background I/O
• Polling web services(資料來源:WebWorker Multitbreaded Programs in Javascript)
當然web worker並不能說是超強神器,他也有不能處理的部份。因為web worker先天的設計是寫在外部js文件之中,所以他無法訪問一些browser的對象,來看看W3C的說法:
• The window object
• The document object
• The parent object
• And, last but not least, they can’t use JavaScript libraries that depend on these
objects to work, like jQuery.
以上簡單來說,web worker一直到最新版的定義都是無法處理大部分的 DOM的操作。
順便來提提,在W3C定義web worker可使用的部份:
• The navigator object
• The location object (read-only)
• The XMLHttpRequest function
• The atob() and btoa() functions for converting Base 64 ASCII to and from binary
data
• setTimeout() / clearTimeout() and setInterval() / clearInterval()
• dump()
• The application cache
• External scripts using the importScripts() method
• Spawning other Web Workers
這是一個很制式化的說法,不過這之中的內容耐人尋味。
首先,看到setTimeout() / clearTimeout() and setInterval() / clearInterval()這些類似異步的寫法,和XMLHttpRequest 異步寫法都是可以寫在webworker的外部文件中,我個人認為是不需要額外把這些東西用web worker去做處理,因為異步的概念其實就很類似web worker,除非是真的要花長時間等待,否則盡量不要用,會延伸到一些安全問題(等等會說明)
The application cache部分,html5 cache API目前也普及在各瀏覽器上,如果能夠利用web worker去減少初次(或者是更新)的時間,對於mobile web開發來說是非常實用的部份。
(關於html5 cache API請詳閱此篇文章:http://mobiforge.com/developing/story/using-html5-application-cache-mobile-web-apps)
簡單介紹一下幾個webworker基礎觀念跟常用的API:
建構web worker,可以選擇的worker有兩種:1.Dedicated workers 2.shared workers
1.Dedicated workers
我們要創建一個 Dedicated worker 方法如下:
var worker = new Worker('extended.js');
這個意思是,創建一個名為worker的web worker thread,而這個thread執行的內容全部都放在名為extended.js的外部文件之中。
當然,你在你的web page若想要與web worker的thread做立即溝通,可以使用postmessage(),至於傳輸的內容常見為JSON(當然不是只有傳JSON, array. binary等等都可以!)
例如:
worker.postMessage ({'cmd': 'start', 'time': Date.now() });
然而,如果你要在web page 端接收從worker thread端的訊息,可用
worker.onmessage = function (e) { ... };
也可這樣寫
worker.addEventListener('message', function(event) {
…
}, false);
不過,請記得每當一個webworker thread 交代的事情結束時,要執行
worker.terminate();
或者是
worker.close();
以釋放瀏覽器資源。
以上是在web page的寫法,在extended.js中的thread要做的事情請這樣寫:
self.addEventListener('message', function(e) { … })
或是
self.onmessage = function(event){ … })
在實務經驗上,在web page中的postMessage()有個常見問題,如果傳送的data非常龐大,傳輸的過程也會導致thread稍晚執行,要改善這個問題其實有方法:
worker.webkitPostMessage(arrayBuffer, [arrayBuffer]);
但是請注意,每當web page 傳送data到web worker,若利用上面的arrayBuffer方式的話,在web worker所產生的 arrayBuffer會把原來在主線程的覆蓋掉,也就無法再次執行原來的arrayBuffer。此外這方法似乎僅適用於chrome 17+
(詳情請見:http://updates.html5rocks.com/2011/12/Transferable-Objects-Lightning-Fast)
講到這邊,順便討論一下webworker data transfer安全問題,我個人會建議,盡量避免用web worker做AJAX取用資料(post or get)方式,因為web worker可以很容易被建構出來(在瀏覽器下指令也可以)這樣容易被有心人士多開thread通道,利用DDos方式大量攻擊server端。
2.Shared workers
共享線程,其實顧名思義就是有一個管道可以讓不同window obj共享worker thread數據,舉個簡單例子來說明:
如果一個html裡面有個iframe方式引用另一個html(當然都在同一個domain下)若要他們皆要引用同一個worker thread 數據,這時候shared worker方式就會派上用場!
var worker = new SharedWorker("extended.js");
至於其他api調用跟Dedicated workers很像,只是要多加個port,例如:
worker.port.start();
worker.port.postMessage();
…等等。
或許,有人會問說如何debug worker?
可以透過onerror API !
var worker = new Worker("worker.js");
worker.onerror = function(e){
….
};
以及chrome 內建的web worker偵測:
那麼在做mobile web一定會很關心支援度問題,webworker在各瀏覽器的支援度如何?
請先參照caniuse:
http://caniuse.com/webworkers
在做關於mobile web專案,Android 系列的瀏覽器需要常注意一下(因為很多都不支援),由上表可看出basic的android browser是不支援web worker, 那麼IE Phone呢? 很抱歉也不支援!
此外,更細節的webworker內部的協議功能支援度還是要注意一下,請參考
https://developer.mozilla.org/en-US/docs/DOM/Using_web_workers
(請見下面的Browser compatibility那欄)
網站也必須放個偵測功能,可以透過一些專案常用的JS plugin去偵測目前用戶browser是否適合web worker:
比如說像是http://modernizr.com/
if (Modernizr.webworkers) {
// window.Worker is available!
} else {
// no native support for Web Workers
}
文章的末端,想再討論一些有趣的事情,是否有人想過worker thread 要幾條會有較好的效能呢?
關於這個問題,我在國外論壇看到以下測試:
http://jsperf.com/webworker-vs-single-thread/7
這個測試結果是非常明顯,首先先看single thread 與 1thread (use worker)在某些版本中1 thread效能是比single thread 差,照理說應該要一樣,但這是可以理解的,有可能是在postMessage()過程浪費了一些效能
然而thread 1 和 2 和 3 和 4 大略來看,thread 2比 thread 1普遍是高於一倍,這似乎很合理,但是從2到3到4則並非很明顯的等差級數般成長(但大多都有接近趨勢),有可能是因為瀏覽器的效能瓶頸。
結論:越多的thread的確會是幫助運算效能,不過要用幾條thread則是看專案需求囉!
全文完
tonyone0902提到:
當然web worker並不能說是超強神器
雖然世上沒有超強神器,但我的神器真的超強...
worker是在client端執行的,跟DDOS不會有關係...除非...你自虐地在網頁中加入Javascript來用多個worker開XMLHttpRequest打自己。
我記得我有寫過用Worker試做壓力測試的文章