就事件回调而言,事件侦听器的优先级在哪里?

时间:2020-06-03 13:05:18

标签: javascript event-handling event-loop

因此在此post中,宏任务队列似乎包含movemouse。但是然后使用此代码

<html>
<body>
    <button id="but_one" onclick='button_one()'>Button 1</button>
    <button id="but_two" onclick='button_two()'>Button 2</button>
</body>
<script>
    //document.addEventListener('mousemove', e => console.log("mouse move"));

    function button_one() {
        console.log("button one")
    }

    function button_two() {
        console.log("button two before")
        setTimeout(() => console.log("timeout : before sleep"), 0)
        autoResolve().then(msg => console.log(".then before sleep " + msg));
        sleep(5000);
        autoResolve().then(msg => {
            sleep(2000);
            console.log(".then after sleep " + msg)
        });
        setTimeout(() => console.log("timeout : after sleep"), 0)
        console.log("button two after")
    }

    function sleep(milliseconds) {
        const date = Date.now();
        let currentDate = null;
        do {
            currentDate = Date.now();
        } while (currentDate - date < milliseconds);
    }

    async function autoResolve() { return "resolved" }
</script>
</html>

如果单击按钮2然后单击1,则可以看到在单击按钮1单击之前,两个诺言(微任务)都已执行,这对我来说很有意义。但是,两个超时(宏任务)似乎都在之后发生,甚至是在我单击之前排队的一个。对我来说,这表明侦听器具有自己的第3个队列,但是没有消息来源这么说。

在记录mousemove时也观察到了同样的情况,但是出于代码控制台中控制台的目的,我删除了该记录。

为什么会这样?

编辑:因此,这是在Windows 10 PC上的Chrome版本83.0.4103.61中完成的

2 个答案:

答案 0 :(得分:2)

该规范说事件循环可能有多个任务队列。这是processing model的第1步:

  1. taskQueue 成为以实现定义的方式选择的事件循环任务队列之一,并限制所选任务队列必须包含至少一个可运行的任务队列任务。如果没有这样的任务队列,请跳到下面的微任务步骤。

(我的重点)

毫不奇怪,浏览器可能(从概念上来说)在单独的任务队列中具有事件和计时器,以便将事件优先于计时器回调,尤其是当该事件由于JavaScript线程太忙而无法处理而被延迟时较早。

我不认为它比“实现定义的方式”更具体。我得到了您在Chrome中描述的行为(计时器回调之前的“按钮一”事件),并且在Firefox事件发生之前得到了计时器回调。

答案 1 :(得分:2)

要运行的宏任务来自多个所谓的任务源。只要每个源的事件顺序发生,浏览器就可以使用多个队列自由决定以什么顺序为它们提供服务。事件监听器和超时是不同的来源,显然您的浏览器认为click事件更为重要。