javascript - 为什么 JS 模态消息框在 setTimeout() 上暂停倒计时?

标签 javascript modal-dialog settimeout alert confirm

alert 等模态对话框窗口打开时,我遇到了 JS setTimeout 的意外行为,我想知道其背后的原因。

我预计 setTimeout(fn,10000) 的意思是“定期检查当前时间,当它大于 Now + 10000 毫秒时触发将调用传递的‘fn’函数的事件处理程序”。这是合乎逻辑的,看看我们如何将超时度量作为“从现在开始的毫秒数”传递。但是,显然,setTimeout 上的倒计时是字面上的倒计时,将在模式窗口打开时暂停。

setTimeout(function(){
    //alert A
    alert("10 seconds have passed for the first setTimeout")
}, 10000);
setTimeout(function(){
    //alert B
    alert("Wait for 15 seconds and press OK");
},1000);

我希望在您关闭警报 B 后立即显示警报 A(假设您等待 15 秒),因为警报 A 超时仅 10 秒并且它们已经过去了。然而,实践表明,当警报 B 打开时,警报 A 的倒计时只是暂停,并且它只会在大约 3 分钟后显示。在您关闭警报 B 后又过了 9 秒,无论 B 打开了多长时间。

这似乎不符合逻辑。

更新。 我绝对不是唯一在这里感到困惑的人,因为这种暂停超时的行为发生在 Chrome 和 Internet Explorer 中,而不是 Firefox。 Firefox 执行了我预期的行为——如果你在警报 B 上等待 15 秒——警报 A 会在你关闭它时立即弹出。

最佳答案

对于为什么 IE 和 Chrome 在 alert 被解除之前暂停未决计时器,而 Firefox 没有,我怀疑是否有明确的答案。我相信这只是因为在解释 W3C's specs for alert 时有一定的自由度。 :

The alert(message) method, when invoked, must run the following steps:

  1. If the event loop's termination nesting level is non-zero, optionally abort these steps.

  2. Release the storage mutex.

  3. Show the given message to the user.

  4. Optionally, pause while waiting for for the user to acknowledge the message.

进一步解释第 4 步(暂停)here :

Some of the algorithms in this specification, for historical reasons, require the user agent to pause while running a task until a condition goal is met. This means running the following steps:

  1. If any asynchronously-running algorithms are awaiting a stable state, then run their synchronous section and then resume running their asynchronous algorithm. (See the event loop processing model definition above for details.)

  2. If necessary, update the rendering or user interface of any Document or browsing context to reflect the current state.

  3. Wait until the condition goal is met. While a user agent has a paused task, the corresponding event loop must not run further tasks, and any script in the currently running task must block. User agents should remain responsive to user input while paused, however, albeit in a reduced capacity since the event loop will not be doing anything.

因此,事件循环在任何情况下都会暂停。当警报仍然可见和模式时,不会调用较长超时的回调。如果不是这样,可能会出现各种麻烦事,例如多个警报叠加在一起。

现在,您能从上面的规范中看出计时器倒计时应该在警报的生命周期内暂停,还是应该在警报消失后立即触发?我不能,我什至不确定哪种行为更合乎逻辑。

我敢肯定的是,除调试目的外,您不应该将 JavaScript 警报用于任何其他用途。警报确实允许暂停脚本执行(而某些异步操作如 XHR 正在后台进行),但它们对用户非常不友好。正确的方法是拥抱异步代码,使用 promises 和可能的 ES6 generators/yeild (如果您追求线性代码风格)。

以下问题高度相关,那里讨论了 alert 的一些替代方法:

关于javascript - 为什么 JS 模态消息框在 setTimeout() 上暂停倒计时?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26487403/

相关文章:

javascript - 在 Javascript 的 for 循环中重置同一计时器的超时

javascript - AMP 如何在页面中包含 javascript 并应用此脚本中的函数

javascript - Mozilla 图像在源更改时闪烁

javascript - 加载时淡入文本

html - Bootstrap 模式不工作

javascript - 为什么 setInterval 中更新的用户名没有反射(reflect)在 View 中

Javascript:在不改变数组的情况下更改数组中元素的值

modal-dialog - 防止模式关闭

javascript - Colorbox 模态不调整大小

javascript - 如何在 forEach 循环中每秒运行一次 setTimeout?