Blackbing Playground

Web Worker 經驗分享(二)

本文章同步刊載於IT邦幫忙

那些年,我們一起讓瀏覽器當掉的日子

昨天提到了 Worker 就像是主從式架構一樣,有要求才有產出,而前後端的任務切割,就是在將商業邏輯與頁面呈現區隔開來。但隨著專案越來越複雜,前端越來越包山包海,我們好像一直不斷的在挑戰瀏覽器一樣,在前端做更多更複雜的事情。

chrome ooops

有了 Worker 之後,或許我們會開始回憶起「那些年,我們一起讓瀏覽器當掉的日子」。

回到主題,那麼到底有哪些情況會用到 Worker 呢?我們先來看看許多專家的說法:

Web Worker的使用案例

  • 影像辨識
  • 影音資料處理
  • 大量資料運算
  • 頻繁或大量的AJAX request
  • 較複雜的字串比對或分析
  • Local 端資料庫的存取
  • File IO (File Reader/Writer API)

以往這些較複雜的運算可能都要透過 server 端來處理,既然前端都可以處理這些事情了,那我們就可以直接在前端處理這些複雜運算,可以再度的節省 server 端的使用。而 Server 端最重要的 Database ,加上 HTML5 LocalStorage 與 IndexDB 可以在前端建立資料庫,拿來做一些簡單的單機系統也會更加容易。

但是這些很複雜的案例,並不是每個專案都有機會碰到,因此我想討論一些更common的案例。

前端可以處理的,就不在後端做

例如上傳圖片,以前都是直接整個檔案直接丟到server端做 resize, crop等等,現在流行前端直接做好再丟到後端。
例如上傳/下載某種檔案支援格式(.txt, .xls, .blabla),server端只要統一好格式,由前端組好在上傳到server端即可。

使用者操作時的「偷偷」動作

使用者在頻繁的操作系統時,如果此時要做一些偷偷背景動作,例如偷偷背景存資料,偷偷背景上傳檔案,讓使用者感覺「Wow,好快速。」例如:「文章自動儲存機制」,「程式碼高亮化(syntax highlight)」等。因為使用者正在操作系統,任何一個動作中斷都會讓使用者覺得系統當掉。

反正重點就是:優化/節省 Server Side 的使用,搾乾 Client Side 的效能(偷笑)。當然,這只是討論,如果有更好的使用案例都歡迎分享。

實作

有了這些基礎概念之後,我們就可以開始實作了。然而在實作上,我很快就遇到第一個問題。通常會需要用到 Worker 來幫忙的,可能會是比較複雜的專案,但中大型專案可能會用到 CoffeeScript 來加速開發的速度,用 RequireJS 來管理模組間的相依性,如果將 Worker 的 script 拆出去,馬上就遇到 Dependency 的問題。舉例來說:

1
worker = new Worker('/worker_path/my_worker.js');

這樣的路徑就失去了用 requirejs 的優勢,破壞了整個專案的 dependency ,如果為了用 Web Worker 而搞砸專案架構,那可是得不償失的,不過幸好,山不轉路轉。

Inline Worker

在 new Worker 時,丟進 Worker 的參數是一個路徑,那麼我們就可以動態產生一個 blob url 路徑,傳給Worker ,動態產生 Woker。

1
2
3
4
5
6
7
8
9
10
content = """
//It is javascript content
var dosomething = function(){
return 'ok dosomething';
};
"""
blobWorker = new Blob([content], {type:'application/javascript'})
blobWorker_url = URL.createObjectURL(blobWorker)
inlineWorker = new Worker(blobWorker_url)
URL.revokeObjectURL(blobWorker_url)

如上,我們就可以動態用 content 來建立 inlineWorker 。只要確保 content 的產生是沒有問題的,用 string 的方式將它讀入就可以建立 Worker。

另外 requireJS 也支援在 worker 裡頭使用,當你的 Worker 要做的事情很多時,可以用 RequireJS 來進行管理,參考requireJS webworker

Debug

Worker 裡頭沒有好用的 console 可以用,不過有 error 的 event 可以註冊。例如:

1
2
3
worker.addEventListener('error', function(error){
console.error(error)
});

另外也可以在 developer tool 裡頭的「Source」開啟「Workers: Pause on start」

debug worker

引用外部程式

Worker 是否可以引用外部程式? 答案是可以的,但需要注意的是它的限制是無法存取瀏覽器資源,所以跟 browser 相關的 API 例如 DOM 都不能用,所以不能使用 jQuery , Backbone 這種與 Browser 相依性很高的 Library (廢話)。

1
importScripts("http://underscorejs.org/underscore.js")

值得一提的是,

access 就會造成整個 Worker 直接死掉。
1
2
3
4
5
6
7
## 釋放Worker
如果確定Worker做完事了,需要結束 Woker 以釋放瀏覽器資源,可以呼叫``terminate``來終結 worker
``` javascript
worker.terminate()

或是直接在 Worker 裡頭自己主動結束

1
self.close()

其他

Worker 其實還定義了 Shared Worker ,可以在不同頁面共享 Worker 的資源,在此不介紹是因為我想不到有比較有意義的應用,有興趣深入瞭解的朋友可以參考 The Basics of Web Workers,裡面有基本的用法介紹。

Just do it

Web Worker 的 API 其實很簡單,難的是在實作上如何將這些動作拆開。建議可以慢慢的將一些動作移到 Worker 來處理,例如 AJAX request ,將資料處理與頁面 render 的程式分開。慢慢的就會更容易的掌握它。

不過不要以為 Web Worker 就這樣結束了,這篇文章其實只是個起點,實際應用在專案上,還會遇到很多問題(嘿嘿~),有任何問題都歡迎提出討論喔 ,我們 2013 JSDC 見。

廣告時間

「影分身好威喔!我也想要!」

HTC One 的 Camera 也可以快速建立多重影分身

參考資料

  1. http://dev.w3.org/html5/workers/
  2. https://developer.mozilla.org/en-US/docs/DOM/Using_web_workers?redirectlocale=en-US&redirectslug=Using_web_workers
  3. http://blog.teamtreehouse.com/using-web-workers-to-speed-up-your-javascript-applications
  4. http://ejohn.org/blog/web-workers/
  5. http://www.html5rocks.com/en/tutorials/workers/basics/
  6. http://debuggable.com/posts/run-intense-js-without-freezing-the-browser:480f4dd6-f864-4f72-ae16-41cccbdd56cb
  7. http://stackoverflow.com/questions/2773682/what-are-the-use-cases-for-web-workers
  8. http://html5hacks.com/blog/2012/09/22/web-workers-basics-of-the-web-browsers-ui-thread/
  9. http://www.html5rocks.com/en/tutorials/workers/basics/#toc-enviornment-subworkers
  10. http://blogs.msdn.com/b/ie/archive/2011/07/01/web-workers-in-ie10-background-javascript-makes-web-apps-faster.aspx
  11. http://blogs.msdn.com/b/davrous/archive/2011/07/15/introduction-to-the-html5-web-workers-the-javascript-multithreading-approach.aspx
  12. http://msdn.microsoft.com/en-us/hh549259.aspx
  13. http://stackoverflow.com/questions/11871452/can-web-workers-utilize-100-of-a-multi-core-cpu?rq=1
  14. http://www.smartjava.org/content/html5-easily-parallelize-jobs-using-web-workers-and-threadpool