2017427日星期四 07:44:51

  在這邊要紀錄一個重要的概念,那就是當我們必須在Client端執行一個JavaSctipt運算時,如果該運算是一個耗時的工作(比方說一個超大迴圈),那麼由於Javascript是單一執行緒的工作特性,所以一旦執行這個運算工作,user勢必得等到該運算完成才能看到網頁最新狀態,這會造成使用者的頁面render卡頓現象,因為在運算完成之前,頁面無法做其他的事。

  所以為解決這個問題,我們可以做的一個方式便是把該大型Javascript運算利用setTimeout方式將其分割成多個小task來批次處理,如此在每個小task執行完成空檔,Client Browser便有空餘時間先插入安排其他非同步工作(如:MouseOnClick),完成後再繼續下一個task,如此網頁的Render便比較不會有卡頓現象,這是一個JavascriptWeb開發時很重要的任務分割以提昇效能的概念,但前提是在類單執行緒的作業環境,在多執行緒環境下,其實這問題是比較小的。

  以下便提供一個我實作自"Secrets of the Javascript Ninja"書本的範例,這個程式是要在使用者頁面用Javascript產生一個有12000 Rows * 6 Cells 的大型表格。 想當然爾傳統做法一定是寫一個簡單的雙迴圈先產生12000 Rows再在每一個產生row的過程建立6cell,但是因為量實在太大,在Javascript產生出這個大表格之前,使用者大概便已經砸了電腦了。

  所以這個範例講會套用前面提到分割任務的概念,先分成6個小task,再依序產生表格內容:

  • Task 1 : Row 0 – 1999
  • Task 2 : Row 2000 – 3999
  • Task 3 : Row 4000 – 5999
  • Task 4 : Row 6000 – 7999
  • Task 5 : Row 8000 – 9999
  • Task 6 : Row 10000 – 11999

  我想這是寫Web時要考慮到的重要概念,以下是程式碼與執行結果,大家有興趣可以試一試用傳統做法或把tasks 變數指定為 1時對於render過程是不是會有很大差異,程式細節我就不多講囉。

DivideJavascriptBigTtask.html

<!DOCTYPE html>

<html>

  <head>

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    <title>Divide Javascript big task to improve the render efficiency</title>

  </head>

  <body>

    <h2>Divide Javascript big task to improve the render efficiency</h2>

    <!-- 注意: 因為執行Javascript 必須參考到 tbody 元素, 所以必需把table的html結構放在javascript之前,否則會發生參考錯誤. -->

     <table border=1>

       <tbody></tbody>

     </table>

    <script>

       var allrows = 12000;  //要建立 12000列

       var tasks = 6;        // 6 cells per row

      var chunk = allrows/tasks; //one task have to generate chunk rows.

      var task_number = 0; //Indicate what task is running.

 

      var t = document.getElementsByTagName("tbody")[0];

     

       //use setTimeout() to process all sub tasks.

      setTimeout(

         function generateRows() {

           var start_row = task_number * chunk;

           for(var i=0; i<chunk; i++) {

             var tr = document.createElement("tr");

              for(var j=0; j<6; j++) {

                var td = document.createElement("td");

                td.appendChild(document.createTextNode("Row " +(i+start_row)+ ", cell " + j + ", in task " + (task_number+1)));

                tr.appendChild(td);

              }

              t.appendChild(tr);

           }

           task_number++;

           if(task_number < tasks) setTimeout(generateRows,0);

         }, 0);    

     </script>

  </body>

</html>

 

Executed Result:

arrow
arrow

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