UI更改事件被阻塞



有两个元素,一个段落和一个按钮。点击按钮后,浏览器会渲染带有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完成。

最新更新