问题描述
摘要
我正在编写带有很多警报/确认的代码,但我发现让所有内容都按应有的方式呈现是一种痛苦。我只希望下面的代码片段按预期工作。首先显示“之前” ,然后等待用户确认警报框。然后应该显示“之后” 。
document.getElementById('display').innerHTML = "Before";
// ALERT
document.getElementById('display').innerHTML = "After";
尝试
我已经尝试过用setTimeout()
在整个SO上百万dupes上推荐的幼稚方式。 (我尝试了零和非零的time
。)
document.getElementById('display').innerHTML = "Before";
alert("Alert Text")
document.getElementById('display').innerHTML = "After";
document.getElementById('display').innerHTML = "Before";
setTimeout(function() {
alert("Alert Text")
},time);
document.getElementById('display').innerHTML = "After";
在第一种情况下,警报停止执行之前,之前的内容尚未完成渲染。第二,下面的内容已经开始渲染,取代了上面的内容。
想法
一个人可以在setTimeout()
块中将所有内容置于警报之下。对于一个警报来说,这不是一个可怕的骇客。但是,有了很多警报,就意味着大量嵌套的setTimeout()
,这在多个级别上似乎是错误的!
简单的sleep()
可以解决所有问题。但是,已被接受的SO answer警告从不在JS中使用sleep()
等效项,而不是setTimeout()
。回到第1格!
TL; DR:使用alert()
以便按顺序呈现前后HTML的最佳方法是什么?
解决方法
请勿使用alert()
或其他任何提示,甚至也不要用于调试。
这些是Web API的旧工件,永远不要使用。
它们具有阻止当前js执行直到关闭的非常奇怪的属性。不同的浏览器将对此进行不同的处理,例如在Firefox中,它们会在发生类似情况时执行"spin the event-loop",从而使事件循环的呈现部分仍然有效,因此在此浏览器中您将看到绘制的更新值。但是,在Chrome中,它们确实完全锁定了事件循环,因此不会进行渲染。
因此解决方案是永远不要依赖这些方法,而要使用HTML和CSS来构建自己的模式。 HTML中有<dialog>
element,可以从头开始完成这种模式,但是任何UI库都有自己的模式(example)。
然后,您只需要侦听close
事件或等效事件即可知道用户何时关闭了该模式:
const dial = document.getElementById("dial");
document.getElementById("display").textContent = "Before";
dial.showModal();
console.log("js execution is not blocked");
// when the modal is closed
dial.addEventListener("close",(evt) => {
document.getElementById("display").textContent =
"After";
},{ once: true });
<div id="display"></div>
<dialog id="dial">
<form method="dialog">
<p>My awesome alert message</p>
<button value="default">OK</button>
</form>
</dialog>
如果您需要比所有这些回调更线性的编码方式,则始终可以使它变差,并使用async / await函数:
const dial = document.getElementById("dial");
function myAlert(message) {
dial.querySelector("p").textContent = message;
dial.showModal();
return new Promise( (res) => {
dial.addEventListener("close",() => res(),{ once: true });
});
}
(async () => {
document.getElementById("display").textContent = "Before";
await myAlert('hello');
document.getElementById("display").textContent = "After";
await myAlert('bye');
})();
dialog {
min-width: 150px;
}
dialog > form > button {
float: right;
}
<div id="display"></div>
<dialog id="dial">
<form method="dialog">
<p>My awesome alert message</p>
<button value="default">OK</button>
</form>
</dialog>