在浏览器中单击物理和编程性之间有什么区别



当我研究事件循环时,我遇到了这个问题。

<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
  1. 当我亲自单击时,JavaScript运行时会将点击拨回任务队列,与此同时,执行调用堆栈为空。

  2. 当我通过编程单击时,JavaScript运行时执行同样的事情,但是 inner.click()在执行呼叫堆栈中。

btw:MDN中有关编程性单击

的解释

那么,在浏览器中单击物理和程序上有什么区别?inner.click()似乎是同步的。

javaScript以单个线程模式运行,这意味着谈论同步vs async有点误导,特别是如果您来自其他语言,例如C或Java。

您运行的所有代码总是运行到完成,从某种意义上说,一切都是同步的,因为您只有一个线程可以运行JS代码(忽略更像单独的过程的Web Worker(。
因此,通常通过回调完成所有I/O处理,以防止阻止单个线程(除了稀有的不弃用异常(例如alert()函数或同步XHR(。有关更多深度解释,请参见此处。
我希望它能清除一些混乱。

最新更新