为什么JS模式消息框在setTimeout()处暂停倒数计时? [英] Why do JS modal message boxes pause countdown on setTimeout()?

查看:140
本文介绍了为什么JS模式消息框在setTimeout()处暂停倒数计时?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当像alert这样的模式对话框窗口打开时,我遇到了JS setTimeout的意外行为,我想知道其背后的原因.

I have encountered an unexpected behavior of JS setTimeout when modal dialog windows like alert are open and I would like to know the reason behind it.

我期望setTimeout(fn,10000)的意思是定期检查当前时间,当当前时间大于Now + 10000ms时,将触发将调用传递的'fn'函数的事件处理程序".看到我们如何通过从现在开始的毫秒数"通过超时度量,这将是合乎逻辑的.但是,显然,setTimeout上的倒数是文字倒数,并且在模式窗口打开时将被暂停.

I expected setTimeout(fn,10000) to mean "check current time periodically and when it is greater than Now + 10000ms fire the event handler that will invoke the passed 'fn' function". This would be logical, seeing how we pass the timeout measure as 'ms from now'. But, apparently, the countdown on setTimeout is a literal countdown and will be paused while a modal window is open.

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后(假设您等待了15秒),警报A将立即显示,因为警报A超时仅10秒钟,并且它们已经过去.但是,实践表明,警报B处于打开状态时,警报A的倒计时只是暂停,并且仅在大约1点后显示.关闭警报B后,无论B开启了多久,都已经过了9秒钟.

I would expect alert A to display immediately after you close alert B (presuming you waited for 15 sec. to do so), since alert A timeout was just for 10 sec and they have already passed. Practice, however, shows that countdown to alert A is simply paused while alert B is open and it will show only after approx. 9 more seconds have passed after you've closed alert B, no matter how long B was open.

这似乎不合逻辑.

更新.我绝对不是唯一一个困惑的人,因为这种暂停超时的行为发生在Chrome和Internet Explorer中,而不是Firefox中. Firefox执行我预期的行为-如果您在警报B上等待15秒钟-每当您关闭警报A时,警报A就会立即弹出.

Update. I'm definitely not the only one confused here, because this behavior of pausing the timeout occurs in Chrome and Internet Explorer, but not Firefox. Firefox executes the behavior I expected - if you wait for 15 seconds on alert B - alert A pops out instantly whenever you close it.

推荐答案

我怀疑对于为什么IE和Chrome都会暂停挂起的计时器,直到alert被解雇,而Firefox却没有,这是否有一个明确的答案.我认为这只是因为在解释 W3C的alert :

I doubt there is a definitive answer on why both IE and Chrome put a pause on pending timers until alert has been dismissed, and Firefox doesn't. I believe it's just because there is certain freedom in interpreting the W3C's specs for alert:

alert(message)方法在被调用时必须运行以下步骤:

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

  1. 如果事件循环的终止嵌套级别为非零,则可以选择 放弃这些步骤.

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

释放存储互斥锁.

向用户显示给定的消息.

Show the given message to the user.

(可选)在等待用户确认 消息.

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

第4步(暂停)进一步说明

Step 4 (the pause) is further explained 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. 如果有任何异步运行的算法正在等待稳定状态, 然后运行其同步部分,然后继续运行其 异步算法. (请参见事件循环处理模型 有关详细信息,请参见上面的定义.)

  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.)

如有必要,更新任何文档的渲染或用户界面 或浏览上下文以反映当前状态.

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

等待直到达到条件目标.当用户代理已暂停时 任务,相应的事件循环不得运行其他任务,并且任何 当前正在运行的任务中的脚本必须被阻止.用户代理应 暂停时仍对用户输入保持响应,尽管 由于事件循环将无法执行任何操作,因此容量降低.

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.

因此,无论如何,事件循环都将被挂起.当警报仍然可见且为模态时,不会调用较长超时的回调.如果不是这样,那么各种各样的丑闻都可能成为可能,例如多个警报相互叠加.

So, the event loop gets suspended in any case. The callback of the longer timeout doesn't get invoked while the alert is still visible and modal. Had it not been this way, all kinds of nasties might be made possible, like multiple alerts on top of each other.

现在,您可以从上述规格中判断是在警报的整个生命周期中暂停计时器倒计时,还是在警报消失后立即将其触发?我不能,我什至不知道哪种行为更合乎逻辑.

Now, can you tell from the above specs if the timer countdown should be suspended for the lifetime of the alert, or should rather be fired as soon as the alert has gone? I can't, and I'm not even sure which behavior would be more logical.

我确定的是,除了调试目的之外,您不应将JavaScript警报用于其他任何用途.警报的确可以暂停脚本的执行(同时在后台进行诸如XHR之类的一些异步操作),但是它们对用户非常不友好.正确的方法是使用promise并可能使用 ES6生成器/yeild (如果您是在线性代码样式之后).

What I'm sure about is that you shouldn't be using JavaScript alerts for anything else but debugging purposes. Alerts do allow to suspend script execution (while some asynchronous operation like XHR is taking place in the background), but they're quite unfriendly to the user. The right approach would be embrace asynchronous code, using promises and, possibly, ES6 generators/yeild (if you're after the linear code style).

以下问题高度相关,并在其中讨论了alert的一些替代方法:

The following question is highly related and some alternatives to alert are discussed there:

这篇关于为什么JS模式消息框在setTimeout()处暂停倒数计时?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆