在Web開發的時候經常會遇到瀏覽器不回應事件進入假死狀態,甚至彈出「腳本運行時間過長「的提示框,如果出現這種情況說明你的腳本已經失控了。
一個瀏覽器至少存在三個執行緒:js引擎執行緒(處理js)、GUI渲染執行緒(渲染頁面)、瀏覽器事件觸發執行緒(控制互動)。
1:JavaScript引擎是基於事件驅動單執行緒執行的,JS引擎一直等待著任務佇列中任務的到來然後加以處理,瀏覽器無論再什麼時候都只有一個JS執行緒在運行JS程式。
2:GUI 渲染執行緒負責渲染瀏覽器介面,當介面需要重繪(Repaint)或由於某種操作引發回流(reflow)時,該執行緒就會執行。但要注意 GUI渲染執行緒與JS引擎是互斥的,當JS引擎執行時GUI執行緒會被掛起,GUI更新會被保存在一個佇列中等到JS引擎空閒時立即執行。
3:事件觸發線程,當一個事件被觸發時該線程會把事件加到待處理佇列的隊尾,等待JS引擎的處理。這些事件可來自JavaScript引擎目前執行的程式碼區塊如setTimeOut、也可來自瀏覽器核心的其他執行緒如滑鼠點擊、AJAX非同步請求等,但由於JS的單執行緒關係所有這些事件都得排隊等待JS引擎處理。
了解了瀏覽器的核心處理方式就不難理解瀏覽器為什麼會進入假死狀態了,當一段JS腳本長時間佔用著處理機就會掛起瀏覽器的GUI更新,而後面的事件回應也被排在佇列中無法處理,造成了瀏覽器被鎖定進入假死狀態。另外JS腳本中進行了DOM操作,一旦JS呼叫結束就會馬上進行一次GUI渲染,然後才開始執行下一個任務,所以JS中大量的DOM操作也會導致事件響應緩慢甚至真正卡死瀏覽器,如在IE6下一次插入大量的HTML。而如果真的彈出了「腳本運行時間過長「的提示框則表示你的JS腳本肯定有死循環或進行過深的遞歸操作了。
現在如果遇到了這種情況,我們可以做的不僅僅是優化程式碼,html5的webWorkers提供了js的後台處理線程的API,它允許將複雜耗時的單純js邏輯處理放在瀏覽器後台執行緒中進行處理,讓js執行緒不阻塞UI執行緒的渲染。這個線程不能和頁面進行交互,如獲取元素、alert等。多個線程間也是可以透過相同的方法進行資料傳遞。
直接看程式碼:
範例:使用者輸入一個數字,進行加法運算(+=)
以前的做法:
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>webworkers--calculate</title> </head> <body> <input id="num" name="num" type="text"/> <button onclick = "calculate()">计算</button><br /> <div id="result" style="color:red;"></div> <div id="time" style="color:red;"></div> <script type="text/javascript" src="calculate.js"></script> <script type="text/javascript"> function calculate(){ data1 = new Date().getTime(); var num = document.getElementById("num").value; var val = parseInt(num,10); var result =0; for(var i =0; i<num;i++){ result += i; } data2 = new Date().getTime(); document.getElementById("result").innerHTML ="计算结果:"+result; document.getElementById("time").innerHTML ="普通 耗时:"+ (data2 - data1)+"ms"; } </script> </body> </html>
使用webWorkers以後使用webWorkers以後使用webWorkers :
calculate.html
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>webworkers--calculate</title> </head> <body> <input id="num" name="num" type="text"/> <button onclick = "calculate()">计算</button><br /> <div id="result" style="color:red;"></div> <div id="time" style="color:red;"></div> <script type="text/javascript" src="calculate.js"></script> <script type="text/javascript"> var worker = new Worker("calculate.js"); var data1 =0; var data2 =0; worker.onmessage = function(event){ var data = event.data; data2 = new Date().getTime(); document.getElementById("result").innerHTML ="计算结果:"+data; document.getElementById("time").innerHTML ="workers 耗时:"+ (data2 - data1)+"ms"; }; function calculate(){ data1 = new Date().getTime(); var num = document.getElementById("num").value; var val = parseInt(num,10); worker.postMessage(val); } </script> </body> </html>
calculate.js
onmessage = function(event){ var num = event.data; var result = 0; for(var i = 0; i<num;i++){ result += i; } postMessage(result); };
webWorker需要將程式碼放入web伺服器中,如果使用的是localhost請使用高版本的chrome瀏覽器打開,firefox瀏覽器在處理localhost的時候會出現「Could not get domain!」的錯誤,
對比上面的兩種實作方式,當計算價值達到100億的時候,普通做法耗時已經很長,而且一般會卡死了。
webWorkers在Chrome15下的效果。 修正:getTime()回傳的應該是毫秒(ms),而不是秒(s)。
普通方法在Chrome15下的效果
可見webWorkers在未來的web應用中還是非常有價值的。
以上是html5 WebWorkers防止瀏覽器假死的範例程式碼分享的詳細內容。更多資訊請關注PHP中文網其他相關文章!