事件回调中事件listeners的优先级在哪里?

问题描述 投票:1回答:2

所以在这个 岗位 ,macrotask队列似乎包括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,你可以看到两个承诺(microtasks)都是在按钮1点击注册之前执行的,这对我来说是合理的。然而两个超时(macrotasks)似乎都发生在之后,甚至在我点击之前排队的那个。对我来说,这表明监听器有自己的第3个队列,但没有来源说这一点。

同样的情况也发生在记录mousemove的时候,不过我在代码片段中为了控制台的目的去掉了这个。

为什么会出现这种情况?

编辑:所以这是在Windows 10 PC上的Chrome 83.0.4103.61版本中完成的。

javascript event-handling event-loop
2个回答
2
投票

规范中说,事件循环可以有多个任务队列。下面是第1步 加工模式:

  1. 任务队列事件循环的任务队列之一,以实现定义的方式选择。,其约束条件是所选的任务队列必须包含至少一个可运行的任务。如果没有这样的任务队列,则跳到下面的微任务步骤。

(我的强调)

浏览器可能会(概念上)在不同的任务队列中设置事件和定时器,以便将事件优先于定时器回调,这并不奇怪,尤其是当该事件因为JavaScript线程太忙而被延迟,无法在之前处理时。

我想除了那个 "实现定义的方式 "之外,没有更多......呃......具体的规定。我用Chrome浏览器得到了你描述的行为(定时器回调前的 "button one "事件),用Firefox得到了事件前的定时器回调。


2
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.