Javascript 为什么JS模式消息框会在setTimeout()上暂停倒计时?
当模式对话框窗口(如Javascript 为什么JS模式消息框会在setTimeout()上暂停倒计时?,javascript,modal-dialog,settimeout,alert,confirm,Javascript,Modal Dialog,Settimeout,Alert,Confirm,当模式对话框窗口(如alert打开时,我遇到了JSsetTimeout的意外行为,我想知道其背后的原因 我希望setTimeout(fn,10000)的意思是“定期检查当前时间,当它大于现在+10000ms时,触发将调用传递的'fn'函数的事件处理程序”。这是合乎逻辑的,看看我们是如何将超时度量值传递为“ms from now”的。但是,显然,setTimeout上的倒计时是一个文字倒计时,在模式窗口打开时将暂停 setTimeout(function(){ //alert A
alert
打开时,我遇到了JSsetTimeout
的意外行为,我想知道其背后的原因
我希望setTimeout(fn,10000)的意思是“定期检查当前时间,当它大于现在+10000ms时,触发将调用传递的'fn'函数的事件处理程序”。这是合乎逻辑的,看看我们是如何将超时度量值传递为“ms from now”的。但是,显然,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);
我希望警报A在您关闭警报B后立即显示(假设您等待了15秒),因为警报A超时时间仅为10秒,它们已经过去了。然而,实践表明,警报A的倒计时仅在警报B打开时暂停,并且仅在关闭警报B后大约9秒后才会显示,无论B打开多长时间
这似乎不合逻辑
更新。我肯定不是这里唯一感到困惑的人,因为暂停超时的行为发生在Chrome和Internet Explorer中,而不是Firefox中。Firefox执行了我预期的行为——如果你在警报B上等待15秒——每当你关闭它时,警报A就会立即弹出 警报是UI阻塞,由于Javascript是单线程的,它将阻止任何东西运行,直到对话框被取消。如果您确实需要,可以使用自己的计时器
var now = Date.now();
function alertA(){
//alert A
alert("10 seconds have passed for the first setTimeout")
}
setTimeout(function(){
//alert B
alert("Wait for 15 seconds and press OK");
setTimeout(alertA, 10000 - (Date.now() - now)); // Subtract the time passed
},1000);
您可以将其包装在实用程序方法中:
function alertDelay(messages, timePassed) {
if (typeof messages !== "object" || messages.length === 0) return;
if (timePassed == null) timePassed = 0;
var firstMessage = messages[0];
var now = Date.now();
setTimeout(function() {
alert(firstMessage.message);
alertDelay(messages.slice(1), Date.now() - now);
}, firstMessage.delay - timePassed);
}
用法:
alertDelay([
{message: 'Message 1', delay: 1000},
{message: 'Message 2', delay: 5000},
{message: 'Message 3', delay: 10000}
]);
我怀疑IE和Chrome为什么会暂停暂停等待的计时器,直到
警报被解除,而Firefox却没有。我相信这只是因为在解释以下内容时有一定的自由:
调用警报(消息)方法时,必须运行以下步骤:
如果事件循环的终止嵌套级别为非零(可选)
中止这些步骤
释放存储互斥锁
向用户显示给定的消息
(可选)在等待用户确认故障时暂停
信息
步骤4(暂停)进一步解释如下:
由于历史原因,本规范中的一些算法,
要求用户代理在运行任务时暂停,直到出现条件
目标实现了。这意味着运行以下步骤:
如果任何异步运行的算法正在等待稳定状态,
然后运行它们的同步部分,然后继续运行它们的同步部分
异步算法。(请参见处理模型
详细信息请参见上述定义。)
如有必要,请更新任何文档的呈现或用户界面
或浏览上下文以反映当前状态
等待条件目标实现。当用户代理暂停时
任务,相应的事件循环不得运行进一步的任务,以及
当前正在运行的任务中的脚本必须被阻止。用户代理应该
但是,在暂停时保持对用户输入的响应,尽管是在
由于事件循环不会执行任何操作,因此容量降低
因此,事件循环在任何情况下都会挂起。当警报仍然可见且处于模式时,不会调用较长超时的回调。如果不是这样的话,各种各样的恶行都可能发生,就像多个警报相互叠加一样
现在,您可以从上面的规范中判断计时器倒计时是应该在警报生命周期内暂停,还是应该在警报结束后立即触发?我不能,我甚至不确定哪种行为更符合逻辑
我确信的是,除了调试之外,您不应该使用JavaScript警报。警报确实允许暂停脚本执行(当某些异步操作(如XHR)在后台进行时),但它们对用户非常不友好。正确的方法应该是采用异步代码,使用承诺,并且可能(如果您追求线性代码样式)
以下问题高度相关,此处讨论了警报
的一些替代方案:
您的意思是说“警报是同步的”。我知道,但这并不能回答问题。我最初的期望是alert A setTimeout在alert B中的函数返回并且JS线程被解锁后立即检查当前时间,在这一点上,它会看到超过10000毫秒已经通过并执行警报A。这就是为什么alert
s不好的原因之一,尤其是在计时功能方面。@soktinpk我们在项目中使用Bootbox之类的东西来发出警报,但有时它不适用,例如,当您需要在关闭页面时警告用户未保存的数据时。我无法想象人们会经常因为这种行为而陷入麻烦,然而,三大浏览器之间的一个主要行为差异是有趣的。警告用户未保存的数据是警报
和/或确认
的一个非常有效的用法。但是,为什么要在显示警报之前稍等一会儿?我不打算等待,情况是这样的:假设您将超时设置为5秒,然后用户尝试离开。消息弹出,在他决定留下来完成工作之前,他花了5秒钟阅读它。在FF中,一旦他关闭,超时将立即触发,但在IE和CR中,它将再等待5秒,使总超时时间达到10秒。我还没有寻找解决方法,我只是好奇为什么。这段代码肯定帮不了什么忙,因为设置超时设置在不同的地方。我能想到的唯一可行的方法就是重载window.setTimeout。要在内部使用尽可能快的setInterval,请维护一个具有到期da的回调列表