Показывает индикатор выполнения при длительном запуске циклов в IE

У меня есть массив JSON с примерно 2000 записями, и мне нужно создать таблицу для отображения данных из этих записей. Поскольку в ней содержится большой объем данных, обработка может вызвать зависание браузера. Поэтому меня попросили отобразить индикатор выполнения, указывающий прогресс. Javascript является однопоточным, я должен использовать Setinterval, чтобы показать прогресс. Но прогресс не отображается правильно в версиях IE, в зависимости от количества записей в массиве. Пожалуйста помоги

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>

введите код сюда

1 ответ

Решение

Пара вещей, которые вы делаете неправильно:

  • Избегайте длинных for циклы при выполнении DOM-манипуляций, которые очень дороги. Вместо этого используйте requestAnimationFrame. RequestAnimationFrame в основном инструктирует браузер, что вы хотите выполнить анимацию (или какое-то вычисление), и запрашивает, чтобы браузер вызвал указанную функцию перед следующей перерисовкой. Другими словами, это как for цикл, но каждая итерация цикла выполняется только тогда, когда браузер решает (когда он может рисовать).
  • Вы создаете 1000 ненужных $("#divProgress") объекты. Используйте кеш. Создать сингл $progressBar а затем использовать его 1000 раз. Та же проблема с $("#tbl tbody") создается 1000 раз.
  • Вы создаете 1000 экземпляров плагина индикатора выполнения. Как вы делаете: $progressBar.progressbar({ value: (i / Loop) * 100}) является конструктором, который создает новый экземпляр индикатора выполнения с таким значением. Используйте сеттер, а не конструктор: $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>

Поддержка старых IE

Если requestAnimationFrame не определен (как это происходит для IE9 и ниже), я называю doRequestFrame вручную.

Другие вопросы по тегам