为何在谷歌控制台运行的JS仅为选择器元素设置最后一个值?
问题:多次为input元素赋值仅保留最后一次结果
我通过选择器获取input元素后多次执行赋值操作,但最终只会保留最后一次的赋值结果。原本是在for循环中进行该操作,简化后的测试代码如下,运行结果和循环场景一致:
var input = document.querySelector("#challengeInput-36757ce5057c429fae3c0ea0a4e65e16-answer"); input.value = 1; sleepFor(2000); input.value = 2; function sleepFor(sleepDuration) { var now = new Date().getTime(); while (new Date().getTime() < now + sleepDuration) { /* Do nothing */ } }
输出效果:input框最终仅显示2,过程中完全看不到1的状态。
原因分析
你使用的sleepFor是同步阻塞式休眠,而JavaScript采用单线程执行模型——当这个while死循环运行时,浏览器的UI渲染线程会被完全占用,根本没有机会更新input的显示状态。
简单说:你先把input.value设为1,但浏览器还没来得及把这个值渲染到页面上,就被sleepFor的循环占住了主线程;直到2秒后循环结束,代码立刻把值改成2,等主线程终于空闲下来,浏览器才会一次性渲染最终的2,所以中间的1永远不会被显示出来。
解决办法
如果想要看到赋值的中间状态,必须用异步方式让出主线程,让浏览器有时间完成渲染,比如用setTimeout替代同步休眠:
var input = document.querySelector("#challengeInput-36757ce5057c429fae3c0ea0a4e65e16-answer"); input.value = 1; setTimeout(function() { input.value = 2; }, 2000);
这样设置完1之后,主线程空闲,浏览器会立即渲染出1;2秒后异步回调执行,再把值改成2,就能看到两次清晰的状态变化。
如果是循环场景(比如要依次设置多个值),不能用同步for循环,得改用异步递推的方式:
var input = document.querySelector("#challengeInput-36757ce5057c429fae3c0ea0a4e65e16-answer"); var values = [1, 2, 3, 4]; var index = 0; function setNextValue() { if (index >= values.length) return; input.value = values[index]; index++; setTimeout(setNextValue, 2000); } setNextValue();
每次赋值后主动让出主线程,给浏览器留出渲染时间,就能看到每个值依次显示的效果了。
内容的提问来源于stack exchange,提问作者Madison Courto
相关产品推荐
相关产品推荐

