理解alert()如何影响浏览器事件循环

17

我考虑在我们的JavaScript实用断言函数中添加alert()

我们是一个Ajax-heavy应用程序,我们的框架(Ext)通过使用setInterval轮询Ajax响应而不是等待readystate==4的方式实现Ajax,导致所有的Ajax回调都在setInterval堆栈上下文中执行——如果有异常/断言失败,通常会静默地失败。

低级别的alert()如何影响浏览器事件循环?消息框定义必须允许win32事件循环抽气(响应mbox按钮)。这是否意味着其他浏览器事件(比如我们的框架生成的未来的setInterval, 调整大小事件等)将被触发? 这会给我带来麻烦吗?

IIRC: 您可以使用Firefox2和Firefox3.5来查看我所说的区别。

alert('1');
setTimeout(function(){alert('2');}, 10);
alert('3');

Firefox 3.5 显示为1-3-2。 Firefox 2[1] 则显示为1-2&3(同时2和3重叠在一起)。我们可以使用从 ActiveX 启动的 win32 mbox 在 IE8 中复制 1-2&3,而不是像过去那样使用警告窗口,这对我们造成了极大的破坏,我希望确保我们不再走这条路。

有没有人能够指向具体的低级资源来解释这种行为,这里的预期行为是什么,以及在低级别上到底发生了什么变化,包括为什么 Firefox 版本间的行为会改变?

[1] 您可以在 Spoon.net 上复制此行为,但我现在无法让它正常工作。我刚在 Firefox 2.0.0.20 的虚拟机中重新生成了它。


非常好的问题。根据我的经验,alert 的实现在不同的浏览器中有很大的差异。一般来说,在这些事情很重要的情况下,我会避免使用 alert,而是使用自定义的(例如 jQuery UI 风格的)对话框。 - Oliver Moran
@Oliver -- 是的,我们实际上选择使用基于DOM的弹出窗口,但我仍然希望了解警报框内部的情况。 - Dustin Getz
1
“消息框必须允许Win32事件循环进行操作” - 一些操作系统(例如Mac OS X)使用嵌套事件循环。警报可能会运行自己的模态事件循环,这会阻塞主事件循环。某些Web浏览器可能会对话框执行类似的操作。 - s4y
2个回答

7

首先,JavaScript中的计时器并不是非常精确。小于30毫秒的时间间隔可能被视为相同,并且实现方式也有所不同。不要依赖任何隐含的顺序。

alert()函数将始终停止事件循环。如果在alert期间发生了事件或者计时器触发,它们将被排队并在事件循环恢复后(即关闭alert框)调用。

看下面的例子:

var hello = document.getElementById('hello')

setTimeout(function(){
  hello.style.backgroundColor = 'lime'
}, 5000)

alert('Stop!')

setTimeout(function(){
  hello.innerHTML = 'collaborate'
}, 20)

setTimeout(function(){
  hello.innerHTML = 'listen'
}, 1000)

有两种可能的结果:
  1. 你在5秒内关闭警告框。随后会设置并在指定时间间隔触发两个计时器。你可以看到事件循环被暂停,因为无论你等多久才关闭警告框,“listen”函数总是需要1秒来执行。

  2. 你花费超过5秒来关闭警告框。第一个计时器(bgColor)已经过去,所以它会立即执行,然后是设置和调用另外两个计时器。

http://jsbin.com/iheyi4/edit

至于计时器,当事件循环停止时,它也“停止了时间”,所以在这种情况下:

i = 0

setInterval(function(){
  document.getElementById('n').innerHTML = ++i
}, 1000)

setTimeout(function(){
  alert('stop')
}, 5500)

无论你花多长时间关闭警报,下一个数字始终是6 - setInterval不会触发多次。 http://jsbin.com/urizo6/edit

“好的观点。一个alert()将始终停止事件循环”,至少,浏览器进程的win32消息泵正在处理wm_paint,因为如果我们移动mbox,它会重新绘制。在FF3+中,setInterval是否等待是因为wm_timer没有处理,还是因为与javascript vm的某些花哨交互?” - Dustin Getz
@Dustin:显然,JavaScript事件循环与Win32事件队列不同(Win32中没有隐式循环)。我非常确定WM_TIMER始终以正常方式处理,只是JavaScript超时的实现方式使其看起来不同。 - T-Bull

1

我无法复制1-2&3的情况,但这里有一个小工具可能会帮助您调试不同浏览器中发生的情况。


@Dustin Getz 没问题,希望能帮到你! - Briguy37

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接