JS惯用的alert无需破坏HTML渲染 摘要尝试想法

问题描述

摘要

我正在编写带有很多警报/确认的代码,但我发现让所有内容都按应有的方式呈现是一种痛苦。我只希望下面的代码片段按预期工作。首先显示“之前” ,然后等待用户确认警报框。然后应该显示“之后”

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>