页面的JavaScript非阻塞更新

时间:2015-03-20 08:34:15

标签: javascript asynchronous

我有以下代码运行循环并按原样更新页面。目前,在整个循环运行之前,页面不会更新。

如您所见,我尝试添加每drawValues次调用一次的绘图函数5000,以将当前值绘制到屏幕上。我的理解是,当更新drawValues时,页面应该更新,然后主循环将继续计算,直到另一个5000循环。

目前,在整个循环运行之前页面不会更新,不知何故忽略了对drawValues的所有其他调用

完整代码段



/*jslint browser: true*/
/*global $, jQuery, alert*/

$(document).ready(function() {
  'use strict';
  var namesAtStart = ["Sam", "John"],
    specialNum = 8,
    amountOfNames = namesAtStart.length,
    counter = [],
    renderCounter = 0,
    x,
    a,
    loopLength,
    number,
    id,
    preId = "content_",
    finalId;

  for (a = 0; a < amountOfNames; a += 1) {
    counter.push(0);
  }

  for (x = 1; x <= specialNum; x += 1) {

    // Start the counter array at zero
    for (a = 0; a < amountOfNames; a += 1) {
      counter[a] = 0;
    }


    loopLength = Math.pow(10, x);
    finalId = preId + loopLength.toString();

    $(".output-small").append('<span id="' + finalId + '"></span>');

    for (a = 0; a < loopLength; a += 1) {
      number = Math.floor((Math.random() * amountOfNames) + 1);
      counter[number - 1] += 1;
      renderCounter += 1;
      if (renderCounter == 5000) {
        drawValues(namesAtStart, counter, finalId, x, a);
      }
      if (a == loopLength - 1) {
        // This is where I am trying to make the code non blocking and async
        drawValues(namesAtStart, counter, finalId, x, a);
      }
    }
  }
});

// This is the part that I want to run when called and update page.
function drawValues(names, counter, finalId, id, currentCount) {
  'use strict';

  var a;
  $("#" + finalId).empty();


  $("#" + finalId).append("<h3>" + Math.pow(10, id).toLocaleString() + "</h1>");

  for (a = 0; a < names.length; a += 1) {
    $("#" + finalId).append(
      names[a] + ": " + counter[a].toLocaleString() + " (" + (counter[a] / currentCount * 100).toFixed(2) + "%)</br>"
    );
  }

  $("#" + finalId).append("Numerical Difference: " + Math.abs(counter[0] - counter[1]) + "</br>");

  $("#" + finalId).append(
    "Percentage Difference: " + Math.abs(
      (counter[0] / currentCount * 100) - (counter[1] / currentCount * 100)
    ).toFixed(6) + "%</br>"
  );

  $("#" + finalId).append("</br>");


}
&#13;
body {} p,
h3 {
  padding: 0px;
  margin: 0px;
}
.container {} .output {} .output-small {
  margin: 20px;
  padding: 5px;
  border: 1px solid rgba(0, 0, 0, 1);
  width: 300px;
  border-radius: 10px;
}
#stats-listing {}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>

<head>
  <link rel="stylesheet" type="text/css" href="styles.css">
</head>
<title>Roll The Dice</title>

<body>
  <div class="container">
    <div class="output" id="stats-listing">
      <div class="output-small"></div>
    </div>
  </div>
  <script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
  <script src="logic.js"></script>
</body>

</html>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:1)

浏览器中用于运行JavaScript的主要UI线程是单线程的。因此,如果您的某项功能需要花费大量时间,则浏览器不会更新显示内容。

要让浏览器有机会更新显示,您需要通过让当前函数结束并通过setTimeout为下一个更新块安排定时回调到另一次运行来回退它。您将不得不尝试使用您想要支持的浏览器来确定定时回调的延迟;有些浏览器对0感到满意(尽快回电),其他浏览器需要更长时间(50 - 50毫秒 - 对于我所知道的每个浏览器来说都足够了。)

这是一个简单的例子,它为页面增加10个盒子,产量,然后再添加10个,产量等等,直到它完成1000个盒子:

(function() {
  var total = 0;
  addBoxes();
  function addBoxes() {
    var n;
    
    for (n = 0; n < 10 && total < 1000; ++n, ++total) {
      box = document.createElement('div');
      box.className = "box";
      document.body.appendChild(box);
    }
    if (total < 1000) {
      setTimeout(addBoxes, 10); // 10ms
    }
  }
})();
.box {
  display: inline-block;
  border: 1px solid green;
  margin: 2px;
  width: 20px;
  height: 20px;
}