一個瀏覽器至少存在三個執行緒:js引擎執行緒(處理js)、GUI渲染執行緒(渲染頁面)、瀏覽器事件觸發執行緒(控制交互)。

JavaScript引擎是基於事件驅動單執行緒執行的,JS引擎一直等待著任務佇列中任務的到來然後加以處理,瀏覽器無論再什麼時候都只有一個JS執行緒在運行JS程式。

GUI 渲染執行緒負責渲染瀏覽器介面,當介面需要重繪(Repaint)或由於某種操作引發回流(reflow)時,該執行緒就會執行。但需要注意 GUI渲染執行緒與JS引擎是互斥的,當JS引擎執行時GUI執行緒會被掛起,GUI更新會被保存在一個佇列中等到JS引擎空閒時立即被執行。

事件觸發執行緒,當一個事件被觸發時該執行緒會把事件添加到待處理佇列的隊尾,等待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 lang="en">
    <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以後:

calculate.html

    <!DOCTYPE HTML>
    <html lang="en"><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在未來的web應用中還是非常有價值的。

arrow
arrow
    文章標籤
    HTML5 瀏覽器
    全站熱搜

    w3design 發表在 痞客邦 留言(0) 人氣()