JavaScript 非阻塞更新页面

标签 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>");


}
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 {}
<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>

最佳答案

浏览器中用于运行 JavaScript 的主 UI 线程是单线程的。因此,如果您有一个需要花费大量时间的函数,浏览器不会更新显示。

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

这是一个简单的示例,向页面添加 10 个盒子,产量,然后添加另外 10 个盒子,产量等,直到完成 1,000 个盒子:

(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;
}

关于JavaScript 非阻塞更新页面,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29162379/

相关文章:

javascript - 如何简化tamejs中的错误处理?

javascript - 将旧函数更新为异步等待

javascript - 包含括号的变量会导致问题

asynchronous - 如何记录异步瘦+sinatra+ Rack 请求?

javascript - setInterval 和事件循环

asynchronous - 如何正确地等到 future 在 Dart 中完成

javascript - 获取用户从网页复制的文本

javascript - Select2 - 从 js 将其设为只读(未禁用!)

javascript - AngularJS - $interpolate 与 $filter

Jquery $.ajax 异步奇怪行为