一:如何使用Worker
Web Worker的基本原理就是在當前javascript的主線程中,使用Worker類加載一個javascript文件來開辟一個新的線程,起到互不阻塞執行的效果,并且提供主線程和新線程之間數據交換的接口:postMessage,onmessage。
那么如何使用呢,我們看一個例子:
- //worker.js
- onmessage =function (evt){
- var d = evt.data;//通過evt.data獲得發送來的數據
- postMessage( d );//將獲取到的數據發送會主線程
- }
HTML頁面:test.html
- <!DOCTYPE HTML>
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
- <script type="text/javascript">
- //WEB頁主線程
- var worker =new Worker("worker.js"); //創建一個Worker對象并向它傳遞將在新線程中執行的腳本的URL
- worker.postMessage("hello world"); //向worker發送數據
- worker.onmessage =function(evt){ //接收worker傳過來的數據函數
- console.log(evt.data); //輸出worker發送來的數據
- }
- </script>
- </head>
- <body></body>
- </html>
Chrome瀏覽器打開test.html后,控制臺輸出 ”hello world” 表示程序執行成功。通過這個例子我們可以看出使用web worker主要分為以下幾部分。
WEB主線程:
1.通過 worker = new Worker( url ) 加載一個JS文件來創建一個worker,同時返回一個worker實例。
2.通過worker.postMessage( data ) 方法來向worker發送數據。
3.綁定worker.onmessage方法來接收worker發送過來的數據。
4.可以使用 worker.terminate() 來終止一個worker的執行。
worker新線程:
1.通過postMessage( data ) 方法來向主線程發送數據。
2.綁定onmessage方法來接收主線程發送過來的數據。
二:Worker能做什么
知道了如何使用web worker ,那么它到底有什么用,可以幫我們解決那些問題呢。我們來看一個fibonacci數列的例子。
大家知道在數學上,fibonacci數列被以遞歸的方法定義:F0=0,F1=1,Fn=F(n-1)+F(n-2)(n>=2,n∈N*),而javascript的常用實現為:
- var fibonacci =function(n) {
- return n <2? n : arguments.callee(n -1) + arguments.callee(n -2);
- };
- //fibonacci(36)
在chrome中用該方法進行39的fibonacci數列執行時間為19097毫秒 ,而要計算40的時候瀏覽器直接提示腳本忙了。
由于javascript是單線程執行的,在求數列的過程中瀏覽器不能執行其它javascript腳本,UI渲染線程也會被掛起,從而導致瀏覽器進入僵死狀態。使用web worker將數列的計算過程放入一個新線程里去執行將避免這種情況的出現。具體看例子:
- //fibonacci.js
- var fibonacci =function(n) {
- return n <2? n : arguments.callee(n -1) + arguments.callee(n -2);
- };
- onmessage =function(event) {
- var n = parseInt(event.data, 10);
- postMessage(fibonacci(n));
- };
HTML頁面:fibonacci.html
- <!DOCTYPE HTML>
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
- <title>web worker fibonacci</title>
- <script type="text/javascript">
- onload =function(){
- var worker =new Worker('fibonacci.js');
- worker.addEventListener('message', function(event) {
- var timer2 = (new Date()).valueOf();
- console.log( '結果:'+event.data, '時間:'+ timer2, '用時:'+ ( timer2 - timer ) );
- }, false);
- var timer = (new Date()).valueOf();
- console.log('開始計算:40','時間:'+ timer );
- setTimeout(function(){
- console.log('定時器函數在計算數列時執行了', '時間:'+ (new Date()).valueOf() );
- },1000);
- worker.postMessage(40);
- console.log('我在計算數列的時候執行了', '時間:'+ (new Date()).valueOf() );
- }
- </script>
- </head>
- <body>
- </body>
- </html>
在Chrome中打開fibonacci.html,控制臺得到如下輸出:
- 開始計算:40 時間:1316508212705
- 我在計算數列的時候執行了 時間:1316508212734
- 定時器函數在計算數列時執行了 時間:1316508213735
- 結果:102334155 時間:1316508262820 用時:50115
這個例子說明在worker中執行的fibonacci數列的計算并不會影響到主線程的代碼執行,完全在自己獨立的線程中計算,只是在計算完成之后將結果發回主線程。
利用web worker我們可以在前端執行一些復雜的大量運算而不會影響頁面的展示,并且不會彈出惡心的腳本正忙提示。
下面這個例子使用了web worker來計算場景中的像素,場景打開時是一片一片進行繪制的,一個worker只計算一塊像素值。
http://nerget.com/rayjs-mt/rayjs.html
三:Worker的其他嘗試
我們已經知道Worker通過接收一個URL來創建一個worker,那么我們是否可以利用web worker來做一些類似jsonp的請求呢,大家知道jsonp是通過插入script標簽來加載json數據的,而script元素在加載和執行過程中都是阻塞式的,如果能利用web worker實現異步加載將會非常不錯。
下面這個例子將通過 web worker、jsonp、ajax三種不同的方式來加載一個169.42KB大小的JSON數據
- // /aj/webWorker/core.js
- function $E(id) {
- return document.getElementById(id);
- }
- onload =function() {
- //通過web worker加載
- $E('workerLoad').onclick =function() {
- var url ='http://js.wcdn.cn/aj/mblog/face2';
- var d = (new Date()).valueOf();
- var worker =new Worker(url);
- worker.onmessage =function(obj) {
- console.log('web worker: '+ ((new Date()).valueOf() - d));
- };
- };
- //通過jsonp加載
- $E('jsonpLoad').onclick =function() {
- var url ='http://js.wcdn.cn/aj/mblog/face1';
- var d = (new Date()).valueOf();
- STK.core.io.scriptLoader({
- method:'post',
- url : url,
- onComplete : function() {
- console.log('jsonp: '+ ((new Date()).valueOf() - d));
- }
- });
- };
- //通過ajax加載
- $E('ajaxLoad').onclick =function() {
- var url ='http://js.wcdn.cn/aj/mblog/face';
- var d = (new Date()).valueOf();
- STK.core.io.ajax({
- url : url,
- onComplete : function(json) {
- console.log('ajax: '+ ((new Date()).valueOf() - d));
- }
- });
- };
- };
HTML頁面:/aj/webWorker/worker.html
- <!DOCTYPE HTML>
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
- <title>Worker example: load data</title>
- <script src="http://js.t.sinajs.cn/STK/js/gaea.1.14.js" type="text/javascript"></script>
- <script type="text/javascript" src="http://js.wcdn.cn/aj/webWorker/core.js"></script>
- </head>
- <body>
- <input type="button" id="workerLoad" value="web worker加載"></input>
- <input type="button" id="jsonpLoad" value="jsonp加載"></input>
- <input type="button" id="ajaxLoad" value="ajax加載"></input>
- </body>
- </html>
設置HOST
- 127.0.0.1 js.wcdn.cn
通過 http://js.wcdn.cn/aj/webWorker/worker.html 訪問頁面然后分別通過三種方式加載數據,得到控制臺輸出:
- web worker: 174
- jsonp: 25
- ajax: 38
多試幾次發現通過jsonp和ajax加載數據的時間相差不大,而web worker的加載時間一直處于高位,所以用web worker來加載數據還是比較慢的,即便是大數據量情況下也沒任何優勢,可能是Worker初始化新起線程比較耗時間。除了在加載過程中是無阻塞的之外沒有任何優勢。
那么web worker是否能支持跨域js加載呢,這次我們通過http://127.0.0.1/aj/webWorker/worker.html 來訪問頁面,當點擊 ”web worker加載” 加載按鈕時Chrome下無任何反映,FF6下提示錯誤。由此我們可以知道web worker是不支持跨域加載JS的,這對于將靜態文件部署到單獨的靜態服務器的網站來說是個壞消息。
所以web worker只能用來加載同域下的json數據,而這方面ajax已經可以做到了,而且效率更高更通用。還是讓Worker做它自己擅長的事吧。
四:總結
web worker看起來很美好,但處處是魔鬼。
我們可以做什么:
1.可以加載一個JS進行大量的復雜計算而不掛起主進程,并通過postMessage,onmessage進行通信
2.可以在worker中通過importScripts(url)加載另外的腳本文件
3.可以使用 setTimeout(), clearTimeout(), setInterval(), and clearInterval()
4.可以使用XMLHttpRequest來發送請求
5.可以訪問navigator的部分屬性
有那些局限性:
1.不能跨域加載JS
2.worker內代碼不能訪問DOM
3.各個瀏覽器對Worker的實現不大一致,例如FF里允許worker中創建新的worker,而Chrome中就不行
4.不是每個瀏覽器都支持這個新特性
【網站聲明】本站除付費源碼經過測試外,其他素材未做測試,不保證完整性,網站上部分源碼僅限學習交流,請勿用于商業用途。如損害你的權益請聯系客服QQ:2655101040 給予處理,謝謝支持。