为什么UI操作在计算后运行,即使两者是交替的?

时间:2016-07-26 14:18:24

标签: javascript jquery

我的问题更复杂,但我已经达到了这个简单的问题。简洁的例子:

HTML:

First: <span id="first"></span> <br/> 
Then: <span id="second"></span> <br/> 
And then: <span id="third"></span> <br/> 
And then: <span id="fourth"></span> <br/> 
And then: <span id="fifth"></span>

JS(+ jQuery(如果有关系)):

$(document).ready(function() {
  doStuff();
});

function doStuff() {
  $("#first").text(new Date().getSeconds());
  var i = 1;
  while (i < 1000000000) {
    i++;
  }
  $("#second").text(new Date().getSeconds());
  var i = 1;
  while (i < 1000000000) {
    i++;
  }
  $("#third").text(new Date().getSeconds());
  var i = 1;
  while (i < 1000000000) {
    i++;
  }
  $("#fourth").text(new Date().getSeconds());
  var i = 1;
  while (i < 1000000000) {
    i++;
  }
  $("#fifth").text(new Date().getSeconds());
}

fiddle

从这个例子中,我的直觉告诉我$("#first")应该在$("#fifth")之前接收文本值。但是,它们都出现在同一时间。不,这不是JS运行得非常快的问题,正如您在示例中看到的那样$("#first")的值比$("#fifth")低约2秒。

为什么会发生这种情况(以及什么!),以及存在哪些解决方案?

2 个答案:

答案 0 :(得分:0)

javascript阻止页面呈现,因此在完成所有javascript块之前,它不会呈现html输出。

答案 1 :(得分:0)

JavaScript在完成之前阻止UI。它应该是一种单线程语言,但是(如this post中所述)并不那么简单。

问题的解决方案是使用setTimeout。请参阅updated simplified fiddle(该示例不适用于复制粘贴,但我相信它足以提出这个想法):

$(document).ready(function() {
  doStuff();
});

function doStuff() {
  $("#first").text(new Date().getSeconds());
  var i = 1;

  setTimeout(function() {
    while (i < 1000000000) {
      i++;
    }
    $("#second").text(new Date().getSeconds());
  }, 0);
}

setTimeout确保doStuff函数完成,然后浏览器处理DOM更改,然后执行另一个函数(传递给setTimeout方法)。

可以找到关于为什么事情以这种方式发生的简明扼要的解释here(感谢@bhspencer提供链接)。简单地说:JS在处理doStuff方法时,UI被阻止(由于其单线程性质)。对第二个参数设置为0毫秒的setTimeout的调用将(立即)放入处理队列中的另一段代码(setTimeout的第一个参数)。然后doStuff方法完成。 JS然后处理队列中的下一个项目 - 显然是UI更新。同样,当UI更新完成后,队列中的下一个项目就是setTimout调用添加的内容。