所以在这个 岗位 ,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版本中完成的。
规范中说,事件循环可以有多个任务队列。下面是第1步 加工模式:
- 让 任务队列 做 事件循环的任务队列之一,以实现定义的方式选择。,其约束条件是所选的任务队列必须包含至少一个可运行的任务。如果没有这样的任务队列,则跳到下面的微任务步骤。
(我的强调)
浏览器可能会(概念上)在不同的任务队列中设置事件和定时器,以便将事件优先于定时器回调,这并不奇怪,尤其是当该事件因为JavaScript线程太忙而被延迟,无法在之前处理时。
我想除了那个 "实现定义的方式 "之外,没有更多......呃......具体的规定。我用Chrome浏览器得到了你描述的行为(定时器回调前的 "button one "事件),用Firefox得到了事件前的定时器回调。
要运行的宏任务来自多个所谓的任务源。浏览器可以自由决定以什么顺序为它们服务,使用多个队列,只要每个源的事件按顺序发生。事件监听器和超时是不同的来源,显然你的浏览器认为点击事件更重要。