不得不說,HTML5確實提供了大量強大的功能特性
甚至顛覆了我們之前理解的JavaScript單線程
它提供了JavaScript多線程的解決方案
這個新特性叫做Web Worker
(在此之前沒有多線程,setTimeout等本質仍然是單線程)
雖然是多線程編程
不過我們不用擔心傳統的多線程語言C++、Java等等遇到的多線程問題
下面我們就來看看什麼是Web Worker
專用Worker(Dedicated Worker)是最常用的Web Worker
而且各個瀏覽器實現的還不錯
什麼時候我們需要多執行緒呢
比如說我們需要複雜的計算、
//demo.jsfunction calculate(){ var ret = 0; for(var i = 1; i <= 1e9; i++){ ret += i; } return ret; }var result;var start;var end; start = +new Date(); result = calculate(); end = +new Date(); console.log(result); //500000000067109000console.log(end - start); //977
我們計算了從1加到10億的值
讓頁面的渲染停了將近1秒鐘
對於用戶的體驗來說是相當不友好的
雖然開發中不會有這麼喪心病狂的計算
但是可能會遇到密集而又複雜的任務
這時我們也許會希望開闢一個獨立的新線程來完成
而我們只需要關注結果值
HTML5允許我們使用Worker執行緒
它的工作內容需要寫在一個獨立的js檔案中
讓我們的多個程式區塊並發運行
var worker = new Worker('scripts/worker.js');
透過這種方式來實例化一個worker
參數是js檔案的路徑(HTML主檔案和Worker檔案需要滿足同源策略)
當程式運行到這裡時
這個檔案就會被載入到一個Worker中
瀏覽器就會啟動一個獨立執行緒運行該js檔案
我們的主執行緒和工作執行緒是基於事件的機制來進行互動的
換句話說,
它們都需要訂閱事件來互相通訊(onmessage事件)
//主线程 worker.addEventListener('message', function(e){ //e.data为从worker线程得到的数据 }); worker.possMessage(...);//向worker线程发送数据
//工作线程 addEventListener('message', function(e){ //e.data为从主线程得到的数据 }); possMessage(...);//向主线程发送数据
它們的資料綁定和資料發送時類似的
只不過在worker檔案中不需要用物件呼叫API
這樣我們剛才的複雜計算就可以讓worker來做
//worker.jsfunction calculate(){ var ret = 0; for(var i = 1; i <= 1e9; i++){ ret += i; } return ret; } postMessage(calculate());
//demo.jsvar worker = new Worker('scripts/worker.js'); worker.addEventListener('message', function(e){ console.log(e.data); //500000000067109000}, false);
在HTML5的Web Worker規範中
worker中還可以實例化它自己的worker(感覺沒什麼必要啊)
稱為subworker(線程嵌套線程)
不過我測試了一下,chrome暫時還不支援subworker
但是據說Firefox支援
既然我們可以創建worker
那麼我們也應該可以終止worker讓它停止工作
在主執行緒和工作執行緒中都可以終止
只需要在worker物件或worker的作用域中呼叫API
一個是我們讓它結束工作
一個是它自己罷工
//主线程worker.terminate();
//工作线程close();
不過我想我們一般情況下
都會以worker物件上呼叫terminate方法的來終止它
這樣會比較安全
#一開始的時候我就說了
我們不必擔心傳統的多線程語言遇到的多線程問題
比如說為了防止它們搶佔資源而引入的…
無比複雜的鎖機制
為什麼呢?
因為在worker內部
我們根本就無法存取主程式的任何資源
它就是一個完全獨立的執行緒
Web Worker有以下限制:
同源策略限制
不能存取頁面DOM和其他資源
#瀏覽器實作程度不同
#不過我們可以在worker內部做這些事情:
可以執行網路操作(Ajax、Web Sockets)
可以使用定時器(set/clearTimeout()、set/clearInterval())
存取某些重要全域變數及功能的複本(navigator、location、JSON、applicationCache)
可以使用importScrips()載入額外js腳本
importScripts('foo.js','bar.js');importScripts('foobar.js');
好奇的話,可以在worker內console.log(this);
查看它的作用域內有什麼
#關於它的應用程式
我們會利用Web Worker做這些事情
複雜數學計算
複雜資料排序
#資料處理(壓縮、影像處理…)
共享Worker
除了專用線程外還有一個共享線程Shared Worker
可以了解一下
到目前為止,只有Google、火狐還有歐朋實現了這個技術
#如果我們的網站或App可以同時載入多個tab (標籤頁)
那麼如果使用普通的worker我們可能會重複創造多個線程
這必然會佔用系統資源
這時如果我們可以讓App或整站的頁面實例都能夠共享一個worker
var worker = new SharedWorker('scripts/worker.js');
由于共享线程需要与多个程序实例或页面链接
所以它需要通过某种方式来了解消息的来源
这个方式就是利用一个唯一标识符port(端口)
这样我们刚才的例子就需要写成这个样子
//demo.jsvar worker = new SharedWorker('scripts/worker.js'); worker.port.addEventListener('message', function(e){ console.log(e.data); //500000000067109000}, false); worker.port.start();
在主线程中
端口连接必须初始化
使用API worker.port.start();
//worker.jsfunction calculate(){ var ret = 0; for(var i = 1; i <= 1e9; i++){ ret += i; } return ret; } addEventListener('connect', function(e){ var port = e.ports[0]; port.start(); port.postMessage(calculate()); });
在共享worker内部同样需要初始化端口连接port.start();
除此之外,我们还需要处理额外事件onconnect
这个事件为我们的特定连接提供了端口对象
而var port = e.ports[0];
用于获取连接分配的端口
我们的onmessage事件就可以写在onconnect事件处理函数内部
addEventListener('connect', function(e){ var port = e.ports[0]; port.addEventListener('message', function(e){ ... port.postMessage(...); ... }); port.start(); });
除此之外,其他的功能共享Worker和专用Worker都是一样的
以上是HTML5多執行緒JavaScript解決方案Web Worker-專用Worker和共享Worker的詳細程式碼介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!