在警报后使用setTimeout在Firefox中以错误的顺序执行代码

时间:2015-05-29 07:14:52

标签: javascript firefox settimeout alert

在任何浏览器中运行以下代码(多次尝试):

console.log('processing: task #1');
setTimeout(function(){
  console.log('processing: task #3');
},0);
alert('See console logs');
console.log('processing: task #2');

根据我的理解,上面的代码会导致控制台输出:

"processing: task #1"
"processing: task #2"
"processing: task #3"

但在Firefox(v38.0.1)中,它会产生以下输出:

"processing: task #1"
"processing: task #3"
"processing: task #2"

请解释为什么Firefox会这样做。不知道它是否是一个bug或Firefox自己的标准。

您可以在此处看到现场演示:http://jsbin.com/cijonu

2 个答案:

答案 0 :(得分:6)

这是一个错误。 HTML5规范不允许事件处理程序在显示警报时触发:

Section 6.1.4定义了事件循环。

在6.1.4.2中,本节还有助于提供有关事件触发顺序的一些保证(事件循环算法的第1点)以及在事件处理程序返回后呈现文档(第4.3点)< / SUP>

Section 6.4定义setTimeout的计时器初始化步骤:

  

...   14. Queue任务task

本节第12点还提供了关于多次超时的相对排序的保证 - 稍后发出的超时可能不会在之前发出的超时之前触发,除非它具有更短的超时

Section 6.5定义alert行为。

  
      
  1. 可选择中止这些步骤。 (例如,用户代理可能会为用户提供忽略所有警报的选项,因此无论何时调用该方法,都会在此步骤中止。)

  2.   
  3. 向用户显示给定的message

  4.   
  5. 在等待用户确认消息时,可选择pause

  6.   

(注意:confirmprompt必须暂停,因为它们会根据用户操作返回

暂停规范说:

  

由于历史原因,本规范中的某些算法要求用户代理在运行任务时暂停,直到满足条件目标。这意味着执行以下步骤:
  ...
  3. 等到条件goal满足。当用户代理具有暂停的任务时,相应的事件循环不能运行更多任务,并且当前正在运行的任务中的任何脚本都必须阻止。用户代理应该在暂停时保持对用户输入的响应,但是,尽管如此因为事件循环不会做任何事情而减少了容量。

(强调我的)

请注意,如果alert没有暂停,控制台日志仍必须按顺序排列:首先同步执行完成(日志#2),然后超时触发(日志#3),然后用户关闭警报。正如页面javascript所观察到的,行为与用户立即关闭警报框的行为相同。

答案 1 :(得分:3)

这是一个Firefox错误。

我已在此处报告:https://bugzilla.mozilla.org/show_bug.cgi?id=1169568