带有ajax的更新元素直到for循环结束才会生效

时间:2018-01-10 09:48:00

标签: javascript jquery ajax long-integer

我想用AJAX打印很多数字。

这样的事情:(每个新行都是前一行的更新!)

output is:
    1
    12
    123
    1234
    12345
    123456
    ...

我经常尝试并阅读了很多同样的问题,但我找不到合适的答案。

真正的问题是javascript中的每个FOR LOOP在END循环后都不会影响DOM。我只想在长时间运行的工作中更新FOR LOOP中的DOM。

请查看我的代码。

$("#btn").on("click", dowork);

function dowork() {
  document.getElementById("foo").innerHTML = "working";
  setTimeout(function() {
    var counter = 100; // i want assign counter = 2000000000
    for (var i = 0; i < counter; i++) {
      document.getElementById("print_here").innerHTML += i;
    }
    document.getElementById("foo").innerHTML = "done!";
  }, 50);
}
#btn {
  background: #1f1f1f;
  padding: 10px;
  font-weight: bolder;
  color: #fff;
  width: 50%;
  margin: auto;
  margin-top: 10px;
  text-align: center;
  cursor: pointer;
}

#print_here {
  overflow-wrap: break-word;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="btn">CLICK TO DO WORK</div>
<div id="foo"></div>
<div id="print_here"></div>

感谢您解决此问题的任何答案和帮助。

3 个答案:

答案 0 :(得分:4)

您的DOM在更新时被“锁定”,并且重新绘制了循环完成的DOM。您可以释放资源,让DOM每次更新时都会更新DOM setTimeout,类似于:

setTimeout(function(){
    document.getElementById("print_here").innerHTML += i;
},1);

确保setTimeout使用i使用let i代替var i

的正确值

$("#btn").on("click", dowork);

function dowork() {
  document.getElementById("foo").innerHTML = "working";

  var counter = 3000; // i want assign counter = 2000000000
  for (let i = 0; i < counter; i++) {
    setTimeout(function() {
      document.getElementById("print_here").innerHTML += i;
    }, 1);
  }
  document.getElementById("foo").innerHTML = "done!";
}
#btn {
  background: #1f1f1f;
  padding: 10px;
  font-weight: bolder;
  color: #fff;
  width: 50%;
  margin: auto;
  margin-top: 10px;
  text-align: center;
  cursor: pointer;
}

#print_here {
  overflow-wrap: break-word;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="btn">CLICK TO DO WORK</div>
<div id="foo"></div>
<div id="print_here"></div>

  

我想把#foo改成“完成!”在FOR语句结束后

您可以检查自己是否在setTimeout内处理的最后一个项目,类似于:

if (i == counter - 1){
    document.getElementById("foo").innerHTML = "done!";
}

$("#btn").on("click", dowork);

function dowork() {
  document.getElementById("foo").innerHTML = "working";

  var counter = 3000; // i want assign counter = 2000000000
  for (let i = 0; i < counter; i++) {
    setTimeout(function() {
      document.getElementById("print_here").innerHTML += i;
      if (i == counter - 1){
        document.getElementById("foo").innerHTML = "done!";
      }
    }, 1);
  }
}
#btn {
  background: #1f1f1f;
  padding: 10px;
  font-weight: bolder;
  color: #fff;
  width: 50%;
  margin: auto;
  margin-top: 10px;
  text-align: center;
  cursor: pointer;
}

#print_here {
  overflow-wrap: break-word;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="btn">CLICK TO DO WORK</div>
<div id="foo"></div>
<div id="print_here"></div>

答案 1 :(得分:1)

您需要让调用堆栈完成,以便浏览器可以在页面上完成其工作。如果您陷入一个主线程,则不会发生页面更新。

执行此操作的一种方法是使用setImmediate或nextTick。这是非标准的,因此请检查此polyfill:https://www.npmjs.com/package/browser-next-tick

基本上,你做一个迭代,然后告诉浏览器尽快进行下一次迭代......这发生在一个新的调用堆栈上。

答案 2 :(得分:-2)

以下是您的工作代码:

#btn {
  background: #1f1f1f;
  padding: 10px;
  font-weight: bolder;
  color: #fff;
  width: 50%;
  margin: auto;
  margin-top: 10px;
  text-align: center;
  cursor: pointer;
}

#print_here {
  overflow-wrap: break-word;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="btn">CLICK TO DO WORK</div>
<div id="foo"></div>
<div id="print_here"></div>
{{1}}

是您要打印的行数。