Javascript setTimeout和UIEvent顺序

Javascript setTimeout和UIEvent顺序,javascript,dom-events,settimeout,uievent,eventqueue,Javascript,Dom Events,Settimeout,Uievent,Eventqueue,如果由于脚本中的某个长时间运行的方法,一组UIEvents被排队,并且在方法IsetTimeout(myfunc,0)的末尾,相对于先前排队的事件的处理程序,myfunc被调用的顺序是什么?是否保证在处理所有以前排队的事件后调用它?浏览器中的大多数事件都是通过中心事件队列以FIFO顺序(先进先出)处理的。某些UI事件(如mousemove事件)会被折叠,以便获得最新状态,而不一定是所有中间事件 所以,问题是鼠标事件何时进入JS事件队列。我真的不确定这是如何工作的,所以我建立了两个测试演示。我发现

如果由于脚本中的某个长时间运行的方法,一组UIEvents被排队,并且在方法I
setTimeout(myfunc,0)
的末尾,相对于先前排队的事件的处理程序,
myfunc
被调用的顺序是什么?是否保证在处理所有以前排队的事件后调用它?

浏览器中的大多数事件都是通过中心事件队列以FIFO顺序(先进先出)处理的。某些UI事件(如mousemove事件)会被折叠,以便获得最新状态,而不一定是所有中间事件

所以,问题是鼠标事件何时进入JS事件队列。我真的不确定这是如何工作的,所以我建立了两个测试演示。我发现答案要视情况而定。如果一个UI事件占用了JS线程,那么看起来其他UI事件没有进入计时器前面的队列,但是如果UI事件完成并且一些其他操作(不在UI上)占用了CPU,那么EVNET将按照适当的FIFO顺序排队。所以,它似乎“取决于”(在Chrome中,这是我到目前为止测试过的)

我将在一秒钟内发布演示的链接

显示如果占用CPU的活动不是对按钮单击的响应,则在
setTimeout()
计划启动之前发生的其他按钮单击将在
setTimeout()之前得到处理

但是,当CPU占用发生在按钮单击事件处理程序中时,情况正好相反。在
setTimeout()
计划启动之前发生的单击在启动之前未得到处理

long
timeout
click
click
click
现在,我在Firefox中运行了这两个程序,发现在这两种情况下Firefox都按照FIFO顺序(按照事件实际发生的顺序)处理事件。对于上面的第二个演示,这与Chrome不同

现在,我在IE中运行了这两个程序,发现IE总是在UI事件之前处理
setTimeout()
,这与Firefox和Chrome都不同

因此,这些测试在三种不同的浏览器中显示了三种不同的结果

总结结果:

Browser      Hog CPU in Event Handler     Hog CPU after Event Handler
---------------------------------------------------------------------
Chrome 44       timeout first (not FIFO)        FIFO clicks first
Firefox 39      FIFO clicks first               FIFO clicks first
IE 11           timeout first (not FIFO)        timeout first (not FIFO)

以下是占用按钮单击事件处理程序CPU的测试用例供参考:

document.getElementById("test").addEventListener("click", function() {
    log("click");
});

document.getElementById("long").addEventListener("click", function() {
    log("long");
    setTimeout(function() {
        log("timeout");
    }, 1900)
    // hhog the CPU here before the event handler finishes
    var t = Date.now();
    while (Date.now() - t < 2000) {}
});
document.getElementById(“测试”).addEventListener(“单击”,函数)(){
日志(“点击”);
});
document.getElementById(“long”).addEventListener(“单击”,函数(){
对数(“长”);
setTimeout(函数(){
日志(“超时”);
}, 1900)
//在事件处理程序完成之前,在此处记录CPU
var t=Date.now();
而(Date.now()-t<2000){
});
下面是一个在按钮客户端事件处理程序完成后占用CPU的测试用例

document.getElementById("test").addEventListener("click", function() {
    log("click");
});

document.getElementById("long").addEventListener("click", function() {
    log("long");

    // schedule a setTimeout
    setTimeout(function() {
        log("timeout");
    }, 1900)

    // hog the CPU, but after the UI event has finished
    setTimeout(function() {
        // spin for 2 seconds to hog the JS thread
        var t = Date.now();
        while (Date.now() - t < 2000) {}
    }, 1);
});
document.getElementById(“测试”).addEventListener(“单击”,函数)(){
日志(“点击”);
});
document.getElementById(“long”).addEventListener(“单击”,函数(){
对数(“长”);
//安排设置超时
setTimeout(函数(){
日志(“超时”);
}, 1900)
//占用CPU,但在UI事件完成后
setTimeout(函数(){
//旋转2秒钟,使JS线程弯曲
var t=Date.now();
而(Date.now()-t<2000){
}, 1);
});

在做了一些测试之后,我不得不编辑我的答案,因为我不正确。是的,UI事件优先于超时。对于超时,似乎无论设置的顺序如何,UI事件都会首先发生。

但是在他调用
setTimeout
之前排队的所有事件呢,它们不会首先执行吗?正是@Barmar,这就是我要问的。当然,我知道我的超时将在长时间运行的方法之后执行。在我运行的测试中,设置超时或事件的顺序似乎并不重要。超时被UI事件阻止了,所以我编辑了我的答案以确保准确性。哇,真奇怪。因此,换句话说,至少在Chrome中,UI事件处理程序阻止其他UI事件在运行时插入队列。@Andy-看起来是这样的,除非我的测试中有缺陷。有些东西告诉我,一定有某个规范的一部分谈到了这应该如何工作,但我还没有找到它。这可能是一种尚未明确规定的行为。对。我希望Firefox的行为方式最终成为规范
document.getElementById("test").addEventListener("click", function() {
    log("click");
});

document.getElementById("long").addEventListener("click", function() {
    log("long");

    // schedule a setTimeout
    setTimeout(function() {
        log("timeout");
    }, 1900)

    // hog the CPU, but after the UI event has finished
    setTimeout(function() {
        // spin for 2 seconds to hog the JS thread
        var t = Date.now();
        while (Date.now() - t < 2000) {}
    }, 1);
});