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

code executed in wrong order in Firefox with setTimeout after 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还是火狐自己的标准。

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

这是一个 Firefox 错误。

我已经在这里报告了:https://bugzilla.mozilla.org/show_bug.cgi?id=1169568

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

Section 6.1.4 定义事件循环。

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

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

... 14. Queue the task task.

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

Section 6.5 定义 alert 行为。

  1. Optionally, abort these steps. (For example, the user agent might give the user the option to ignore all alerts, and would thus abort at this step whenever the method was invoked.)

  2. Show the given message to the user.

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

(注意:confirmprompt 必须暂停,因为它们 return 基于用户操作)

暂停规范说:

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

(强调我的)

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