为什么超时在“;点击“;事件循环在Firefox上完成

Why does the timeout fire before the "click" event loop is complete on Firefox?

本文关键字:Firefox 点击 超时 为什么 事件 循环      更新时间:2023-09-26

步骤:

  1. 在Firefox中运行代码
  2. 等待5秒(重要!)
  3. 按"确定"或"取消"
  4. 期望标志==0,但它是10

var flag;
function myFunction(){
    flag = 0 
    console.info("initial", flag);
    setTimeout(function(){
        flag = 10;
    }, 200);
  
    confirm("conf");
   
    alert("should be 0: "+flag);
}
document.getElementById('button').onclick=myFunction;
   
                          
<button type="button" id="button">Click Me!</button>

因为与许多浏览器不同,Firefox可能允许JavaScript线程在显示alertpromptconfirm模式时运行其他代码,从而暂停当前代码。(有关该句中"可能"的更多信息,请参阅答案末尾。)调用alert等的任务已挂起,因此该任务中的代码不会继续,但允许运行其他任务。

这意味着

  • 计时器可以获得他们的回调

  • Ajax完成处理程序可以运行

  • 等等。

从来没有JavaScript在两个地方同时运行,但Firefox确实允许线程在任务被这些模式挂起时运行其他任务。

这是Firefox的怪癖。多亏了bobince,我第一次在Stack Overflow上了解到它。


为什么我说"可能"允许JavaScript线程运行:它过去相当可靠(Firefox的旧版本)。我在Firefox 29或38上复制它时没有遇到任何问题。Firefox 42似乎降低了这种可能性,但它确实仍然存在。

我预计(尽管我可能错了)Mozilla会改变这一点,以与其他浏览器保持一致,因为有人可能会认为这违反了JavaScript的任务运行到完成语义,而这些语义刚刚在最新规范中得到了加强和澄清。

我在Firefox和Chrome中都尝试过。在Firefox中,我得到了10作为结果。在Chrome中,我得到了0作为结果。当涉及到confirm函数时,Firefox和Chrome可能有不同的并发模型。Firefox可能在一个单独的线程中运行模式对话框,允许setTimeout在自己的线程中继续运行(并在200毫秒后递增flag的值)。Chrome可能在与setTimeout相同的线程中运行模式对话框,从而阻止setTimeout的运行(并且不允许flag的值递增)。

什么?您标志设置为10。你为什么期望它是0?