Javascript innerHTML可以';不可信:不总是同步执行
要查看实际问题,请参阅。单击按钮会触发Javascript innerHTML可以';不可信:不总是同步执行,javascript,Javascript,要查看实际问题,请参阅。单击按钮会触发按钮Handler(),如下所示: function buttonHandler() { var elm = document.getElementById("progress"); elm.innerHTML = "thinking"; longPrimeCalc(); } 您可能希望此代码将div的文本更改为“thinking”,然后运行longPrimeCalc(),这是一个需要几秒钟才能完成的算术函数。然而,事实并非如此。相反,“lon
按钮Handler()
,如下所示:
function buttonHandler() {
var elm = document.getElementById("progress");
elm.innerHTML = "thinking";
longPrimeCalc();
}
您可能希望此代码将div的文本更改为“thinking”,然后运行longPrimeCalc()
,这是一个需要几秒钟才能完成的算术函数。然而,事实并非如此。相反,“longPrimeCalc”首先完成,然后文本在运行完成后更新为“thinking”,就像两行代码的顺序颠倒了一样
看起来浏览器并没有同步运行“innerHTML”代码,而是为其创建一个新线程,该线程在空闲时执行
我的问题是:
longPrimeCalc()
”之前强制它更新“innerHTML”我在最新版本的chrome上对此进行了测试。你的猜测是错误的。
.innerHTML
更新会同步完成(而且浏览器肯定不会创建新线程)。在代码完成之前,浏览器根本不需要更新窗口。如果要以某种需要更新视图的方式查询DOM,那么浏览器将别无选择
例如,在设置innerHTML
之后,添加以下行:
var sz = elm.clientHeight; // whoops that's not it; hold on ...
编辑-我可能会想出一种欺骗浏览器的方法,或者这是不可能的;确实,在单独的事件循环中启动长时间计算将使其工作:
setTimeout(longPrimeCalc, 10); // not 0, at least not with Firefox!
这里一个很好的教训是,浏览器努力避免对页面布局进行无意义的重新流动。如果您的代码在素数休假时出错,然后再次回来更新
innerHTML
,那么浏览器将保存一些无意义的工作。即使它没有绘制更新的布局,浏览器仍然必须弄清楚DOM发生了什么,以便在查询元素大小和位置时提供一致的答案
longPrimeCalc
会导致执行更多的代码,并且只有在完成后页面更新才会更改setTimeout
来完成此操作。我不确定除此之外还有没有别的办法longPrimeCalc
,只需创建另一个函数,该函数根据您的需要处理返回值。基本上,您希望将计算推迟到另一个“线程”执行。以这种方式编写代码可以让您清楚地知道自己在做什么(再次更新以使其可能更好):
setTimeout(longPrimeCalc,50)代码>将解决此问题。而且:“但是创建了一个新线程”不,js只有一个活动线程。0
而不是50
也是有效的(而且更自我解释)。@Xaerxess是的,但在这种特殊情况下,Firefox利用了这一点,并继续推迟重新流程@尖锐的Oops,在我的代码库中似乎几乎没有可能的bug:(应该注意的是,这一切都与.innerHTML
没有任何关系。对于任何DOM操作,您都会得到与预期重画相同的行为。您有没有需要更新视图的示例?那么我如何按照您的建议进行查询:)我尝试放置控制台.log(elm.innerHTML);
在两行代码之间,但这没有任何效果。也就是说,我的问题的答案是什么?#2?@MartinSmith我只是想找一些简单的东西;我会更新answer@Jonah答案更新-关键是询问浏览器一些只有在重做时才能回答的问题layout@Pointy,我仍然看到同样的行为IOR和以前一样:(1,你没有给现有的答案和评论添加任何东西。”Gordon:Jonah说:“考虑在“LoimPrimeCalc”计算中显示“思考”的更真实的世界用法,并在完成后返回到Orrg文本。现在StimeTimeOn首先要调用“LimePrimeCalc”。“,然后使用一些函数将文本返回到orig。或者更糟的是,我可以通过longPrimeCalc进行回调。我真的希望有更好的方法…”在他的评论中。这是一个解决方案,但这两种方法都不起作用。@Claudiu,我没有投你反对票,但这对我不起作用,也就是说,它没有显示“思考”“在计算过程中。这实际上意味着这个setTimeout方法甚至不能作为黑客手段工作……所以,这确实有助于讨论。@乔纳:哦,有趣。我想你试过JS小提琴?你到底在使用什么浏览器?@Claudiu,哈,实际上它甚至在你将1改为2时开始工作
function defer(f, callback) {
var proc = function() {
result = f();
if (callback) {
callback(result);
}
}
setTimeout(proc, 50);
}
function buttonHandler() {
var elm = document.getElementById("progress");
elm.innerHTML = "thinking...";
defer(longPrimeCalc, function (isPrime) {
if (isPrime) {
elm.innerHTML = "It was a prime!";
}
else {
elm.innerHTML = "It was not a prime =(";
}
});
}