有两个元素,一个段落和一个按钮。点击按钮后,浏览器会渲染带有p
标签的文本"Waiting"
,等待3秒后再渲染"Done"
。它运行,但文本"Waiting"
从未呈现。
我知道这可以用setTimeout
解决,但我试图理解为什么文本"Waiting"
根本不出现。
html:
<p id="p">Ready</p>
<button id="button">Start</button>
Javascript:
const pTag = document.getElementById('p');
const button = document.getElementById('button');
button.onclick = () => {
pTag.innerText = 'Waiting';
syncWaitSeconds(3)
pTag.innerText = 'Done';
};
function syncWaitSeconds(seconds = 3){
const start = Date.now();
const time = seconds * 1000
while (Date.now() - start <= time) {
// waiting 3 seconds
}
}
我正在学习Javascript,我想知道为什么文本没有出现。作为改变innerText不返回一个承诺,是同步的,它不应该先发生,然后等待3秒,最后渲染文本'完成' ?
这是因为你在忙着等待,也就是说,你的浏览器太忙了,总是比较这些日期,它根本没有更新UI。这是异步需求的一个很好的例子。它不是"只是"。innerText
没有刷新,当这个忙等待发生时,整个UI都没有响应。
这就是为什么您需要通过setTimeout
异步执行此操作。无setTimeout
:
const pTag = document.getElementById('p');
const button = document.getElementById('button');
button.onclick = () => {
pTag.innerText = 'Waiting';
syncWaitSeconds(3)
pTag.innerText = 'Done';
};
function syncWaitSeconds(seconds = 3){
const start = Date.now();
const time = seconds * 1000
while (Date.now() - start <= time) {
// waiting 3 seconds
}
}
<p id="p"></p>
<button id="button">My Button</button>
WithsetTimeout
:
const pTag = document.getElementById('p');
const button = document.getElementById('button');
button.onclick = () => {
pTag.innerText = 'Waiting';
setTimeout(function() {
pTag.innerText = 'Done';
}, 3000);
};
<p id="p"></p>
<button id="button">My Button</button>
我有更多的解释,在这里分享
我得到的解释是有两个线程,处理Javascript的JS主线程和处理UI更改(包括CSS更改)的浏览器绘制线程,并且两者之间存在线程同步。
将任务更改为"等待";执行和绘画线程应该处理它,但它等待,因为JS调用堆栈不是空的。因此,只有当JS代码不运行时,JS和CSS的UI更改才会发生。
在syncWaitSecond之后,线程呈现了"等待";和";Done"但它是如此之快,我们只看到'完成',或者可能有一些优化的合成步骤,只有'完成'被渲染,但这些变化只发生在JS调用堆栈是空的。
当我们使用setTimeout这样做时,调用堆栈立即为空并"等待";呈现。3秒后,setTimeout返回堆栈,执行代码将文本更改为'Done'。这个任务被添加到UI线程的队列中,但UI线程会再次等待JS代码完成后再绘制"Done"。这些都是有趣的东西,让我了解到JS和浏览器领域有很多我不知道的东西。
更疯狂的是,如果你的JS代码被阻塞了,即使CSS改变,如改变背景颜色悬停将不起作用,因为这也由这个绘画线程处理,并将等待JS完成。