我有以下 JavaScript。所附代码是相当复杂的自动生成的 JavaScript 的极其简化的版本,它在许多对象上启动相同的函数(不是在循环中,而是生成了一堆函数调用)。
问题是代码应该在每次启动函数时更新一个元素。然而,这种情况并没有发生。相反,当我按下按钮时,它会卡住并仅在执行所有功能后更新状态(至“完成”)。那么为什么在以下代码中每次调用 long_function()
时元素都没有更新(以及如何解决这个问题):
<html>
<body>
<h1 id="status">Not yet started</h1>
<button onclick="perform()"> Start! </button>
<script type="text/javascript">
function sleepFor( sleepDuration ){
var now = new Date().getTime();
while(new Date().getTime() < now + sleepDuration){ /* do nothing */ }
}
function long_function(number)
{
document.getElementById("status").innerHTML = number;
sleepFor(1000);
}
function perform(number) {
long_function(1);
long_function(2);
document.getElementById("status").innerHTML = "Done";
}
</script>
</body>
</html>
(该问题发生在 Google Chrome 和 Safari 中)
( sleep 功能取自 What is the JavaScript version of sleep()? 的答案)
最佳答案
这就是我对发生的事情的理解:
- 函数
perform()
运行,并首先调用long_function(1)
。 innerHTML
调用已发送。sleepFor(1000)
函数被调用,但浏览器尚未呈现innerHTML
更改。- 实时编译器通过
sleepFor()
中的while
循环运行,这本质上是阻塞(它会阻止其他 JavaScript 代码运行)但它也会阻止浏览器渲染)。 - 一旦
while
循环完成,JavaScript 就会继续将元素的innerHTML
设置为“完成”,但它永远不会渲染number
在long_function()
中。
如果您想对事件循环、阻塞和非阻塞 JavaScript 进行有趣的观察,这里有一些资源:
由于标题,这个问题有点误导(innerHTML
实际上并不异步运行),但答案很有趣:
innerHTML can't be trusted: Does not always execute synchronously
关于JavaScript 不会在按钮触发的重复操作上更新 Status Div,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39302205/