2

I have a JSON array with around 2000 records and I need to build a table to display the data from these records.As it has large amount of data the processing may cause the browser to freeze.So I was asked to display a progress bar indicating the progress. Javascript being single threaded i have to use Setinterval to show progress.But the progress is not shown correctly in IE versions,depending on the number of records in the array. Please help

var g_arr = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'];

$("#btn").click(function() {

  var Loop = 1000;
  $("#tbl tbody td").remove();
  $("#divProgress").progressbar({
    value: 0
  });
  //window.setTimeout(function(){
  for (var i = 0; i < Loop; i++) {
    var TR = $("<tr>");
    $.each(g_arr, function(index, val) {
      var TD = $("<td>");
      TD.append(val);
      TR.append(TD);
    });
    window.setTimeout(function() {
      $("#divProgress").progressbar({
        value: (i / Loop) * 100
      });
    }, 3000);
    $("#tbl tbody").append(TR);

  }
  //},0);
});
td,
th,
table {
  border-color: black;
  border-width: thin;
  border-style: solid;
  border-collapse: collapse;
}
<link href="http://code.jquery.com/ui/1.10.0/themes/smoothness/jquery-ui.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.min.js"></script>


<div id="divProgress"></div>
<div id="divBody">
  <input type="button" id="btn" value="Click Here" />
  <table id="tbl">
    <thead>
      <tr>
        <th>
          Column1
        </th>
        <th>
          Column2
        </th>
        <th>
          Column3
        </th>
        <th>
          Column4
        </th>
        <th>
          Column5
        </th>
        <th>
          Column6
        </th>
        <th>
          Column7
        </th>
        <th>
          Column8
        </th>
      </tr>
    </thead>
    <tbody>

    </tbody>
  </table>
</div>

enter code here

Intruder
  • 147
  • 1
  • 12
  • 1
    I had the same problems with large amount of data, best solution for me was just simply display "Loading..." Instead of some animated loader, because they get stuck anyway – Tomas Jun 23 '15 at 07:55
  • At first I thought of Placing a Loading gif...But it too gets stuck..anyways Tom your suggestion is appreciated,that would be my final try – Intruder Jun 23 '15 at 08:45
  • you can also make it more dynamic, by adding percentage: "Loading... 10%" but that will get stuck too, so you will see jumps from 10 to 40 etc. But it does make it more dynamic – Tomas Jun 23 '15 at 09:04
  • @Noval please check my update to support IE9 and below. – Jose Rui Santos Jun 23 '15 at 09:43

1 Answers1

4

Couple of things you are doing wrong:

  • Avoid long for loops while doing DOM manipulations, which are very expensive. Use requestAnimationFrame instead. RequestAnimationFrame basically instructs the browser that you wish to perform an animation (or some kind of computation) and requests that the browser call a specified function before the next repaint. In other words, its like a for loop, but each loop iteration runs only when the browser decides (when it can paint).
  • You are creating 1000 unnecessary $("#divProgress") objects. Use cache. Create a single $progressBar and then use it 1000 times. Same problem with $("#tbl tbody") being created 1000 times.
  • You are creating 1000 progress bar plug-in instances. The way you are doing: $progressBar.progressbar({ value: (i / Loop) * 100}) is a constructor that creates a new progress bar instance with such value. Use the setter, not the constructor: $progressBar.progressbar("value", (i / Loop) * 100).

    var g_arr = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'];

    $("#btn").click(function() {

      var i = 0,
          Loop = 1000,
          $progressBar = $("#divProgress"),
          $body = $("#tbl tbody"),
          requestAnimationFrame =
              window.requestAnimationFrame ||
              window.mozRequestAnimationFrame ||
              window.webkitRequestAnimationFrame ||
              window.msRequestAnimationFrame,
          
          doRequestFrame = function () {
              if (i++ < Loop) {
                  $progressBar.progressbar("value", (i / Loop) * 100);
                
                  var $newRow = $("<tr>");
                  $.each(g_arr, function(index, val) {
                    $newRow.append($("<td>").append(val));
                  });
                  $body.append($newRow);

                  if (requestAnimationFrame) {
                      // hey browser, please call again doRequestFrame() when you are idle (before repaint)
                      requestAnimationFrame(doRequestFrame);
                  } else {
                      setTimeout(doRequestFrame, 1);
                  }
              }
          };

      $("#tbl tbody td").remove();
      
      $progressBar.progressbar({
        value: 0
      });
      
      // hey browser, please call doRequestFrame() when you are idle (before repaint)
      requestAnimationFrame ? requestAnimationFrame(doRequestFrame) : doRequestFrame();
    });
td,
th,
table {
  border-color: black;
  border-width: thin;
  border-style: solid;
  border-collapse: collapse;
}
<link href="http://code.jquery.com/ui/1.10.0/themes/smoothness/jquery-ui.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.min.js"></script>


<div id="divProgress"></div>
<div id="divBody">
  <input type="button" id="btn" value="Click Here" />
  <table id="tbl">
    <thead>
      <tr>
        <th>
          Column1
        </th>
        <th>
          Column2
        </th>
        <th>
          Column3
        </th>
        <th>
          Column4
        </th>
        <th>
          Column5
        </th>
        <th>
          Column6
        </th>
        <th>
          Column7
        </th>
        <th>
          Column8
        </th>
      </tr>
    </thead>
    <tbody>

    </tbody>
  </table>
</div>

Support for older IE

If requestAnimationFrame is not defined (as it happens for IE9 and below), I am calling the doRequestFrame manually.

Jose Rui Santos
  • 15,009
  • 9
  • 58
  • 71
  • I would NOT use requestAnimationFrame if you care at all about compatibility. All other points are spot on – Tomas Jun 23 '15 at 09:08
  • hi Jose,anyways thankyou for pointing out the mistakes,I will rectify that..but coming back to progress issue , i saw that requestAnimationFrame would only work for IE 9 + versions – Intruder Jun 23 '15 at 09:14
  • 1
    @Tom Please check my update. You should use graceful degradation, if `requestAnimationFrame` is not supported, then use it the conventional way. – Jose Rui Santos Jun 23 '15 at 09:42
  • Thanks Jose u just saved the day.I replaced the requestAnimationFrame inside the doRequestFrame function with window.setTimeout(doRequestFrame,0); ....Now its working in all versions of IE – Intruder Jun 23 '15 at 10:01
  • @Noval Great, but let the browser use requestAnimationFrame if it supports it, as you can see in my code sample. – Jose Rui Santos Jun 23 '15 at 10:09