当我研究事件循环时,我遇到了这个问题。
<html>
<head>
<style>
#outer {
width: 200px;
height: 200px;
background-color: red;
display: flex;
justify-content: center;
align-items: center;
}
#inner {
width: 100px;
height: 100px;
background-color: yellow;
}
</style>
</head>
<body>
<div id="outer">
<div id="inner"></div>
</div>
</body>
<script>
const inner = document.getElementById("inner");
const outer = document.getElementById("outer");
new MutationObserver(() => console.log("mutate")).observe(outer, { attributes: true });
function onClick(e) {
var id = e.currentTarget.id;
console.log(`${id} click`);
setTimeout(() => console.log(`${id} timeout`), 0);
Promise.resolve().then(() => console.log(`${id} promise`));
outer.setAttribute("data-mutation", Math.random());
}
inner.addEventListener("click", onClick);
outer.addEventListener("click", onClick);
</script>
</html>
当我单击内部块时,结果打印如下:
inner click
inner promise
mutate
outer click
outer promise
mutate
inner timeout
outer timeout
然后我添加一些代码
inner.click();
console.log("end");
在脚本的底部,并以编程方式触发事件。
<html>
<head>
<style>
#outer {
width: 200px;
height: 200px;
background-color: red;
display: flex;
justify-content: center;
align-items: center;
}
#inner {
width: 100px;
height: 100px;
background-color: yellow;
}
</style>
</head>
<body>
<div id="outer">
<div id="inner"></div>
</div>
</body>
<script>
const inner = document.getElementById("inner");
const outer = document.getElementById("outer");
new MutationObserver(() => console.log("mutate")).observe(outer, { attributes: true });
function onClick(e) {
var id = e.currentTarget.id;
console.log(`${id} click`);
setTimeout(() => console.log(`${id} timeout`), 0);
Promise.resolve().then(() => console.log(`${id} promise`));
outer.setAttribute("data-mutation", Math.random());
}
inner.addEventListener("click", onClick);
outer.addEventListener("click", onClick);
inner.click();
console.log("end");
</script>
</html>
我得到了不同的结果,如下所示:
inner click
outer click
end
inner promise
mutate
outer promise
inner timeout
outer timeout
当我亲自单击时,JavaScript运行时会将点击拨回任务队列,与此同时,执行调用堆栈为空。
当我通过编程单击时,JavaScript运行时执行同样的事情,但是
inner.click()
在执行呼叫堆栈中。
btw:MDN中有关编程性单击
的解释那么,在浏览器中单击物理和程序上有什么区别?inner.click()
似乎是同步的。
javaScript以单个线程模式运行,这意味着谈论同步vs async有点误导,特别是如果您来自其他语言,例如C或Java。
您运行的所有代码总是运行到完成,从某种意义上说,一切都是同步的,因为您只有一个线程可以运行JS代码(忽略更像单独的过程的Web Worker(。
因此,通常通过回调完成所有I/O处理,以防止阻止单个线程(除了稀有的不弃用异常(例如alert()
函数或同步XHR
(。有关更多深度解释,请参见此处。
我希望它能清除一些混乱。