You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么focusIn处理器中的setTimeout先于click处理器执行?

问题描述

我原本认为不管浏览器内部事件序列如何,DOM事件处理都应该是同步的。但我发现点击(click)处理器存在严重延迟(在我的Macbook Pro M1 Max、Chrome 126.0.6478.63上延迟30-90ms不等),导致setTimeout和requestAnimationFrame中的代码都先于click处理器执行。有人能解释这种行为吗?

最小可复现示例(MVCE)

JavaScript代码

const css = `:host(:focus-within) div { outline: 1px solid blue; display: inline-block; }`;
const sheet = new CSSStyleSheet();
sheet.replaceSync(css);

customElements.define(
  "a-b",
  class extends HTMLElement {
    input = document.createElement("input");
    btn = Object.assign(document.createElement("button"), {
      textContent: "Click me"
    });

    constructor() {
      super().attachShadow({ mode: "open" }).adoptedStyleSheets.push(sheet);
      this.shadowRoot.append(this.input, this.btn);
      this.addEventListener("focusin", this.handleFocusIn);
      this.addEventListener("click", this.handleClick);
    }

    handleFocusIn() {
      output.value += `focusin: ${Date.now()}\n`;
      setTimeout(() => {
        // 为什么这段代码会在click监听器之前执行?
        output.value += `timeout: ${Date.now()}\n`;
      }, 0);
      requestAnimationFrame(() => {
        // 为什么这段代码会在click监听器之前执行?
        output.value += `rAF: ${Date.now()}\n`;
      });
    }
    handleClick() {
      output.value += `click: ${Date.now()}\n----------------------\n`;
    }
  }
);

CSS代码

textarea {
  height: 12em;
  margin-top: 2em;
  width: 16em;
}

HTML代码

<a-b></a-b>
<br>
<textarea id="output"></textarea>
问题解答

这是浏览器的双击检测机制和事件队列执行顺序共同作用的结果:

  • 点击按钮时,浏览器先触发focusin事件(按钮获得焦点),这个事件同步执行,handleFocusIn立刻运行,此时setTimeout(0延迟)被加入宏任务队列,requestAnimationFrame被加入渲染前的回调队列。
  • 为了判断这次点击是不是双击的第一次点击,浏览器会故意延迟click事件的触发(通常在200ms内),这段等待时间里,浏览器会优先处理队列中已有的任务。
  • requestAnimationFrame的回调会在下一次页面重绘前执行,而setTimeout的回调会在当前宏任务结束后立即执行,两者都会在延迟的click事件触发前完成,所以就出现了timeout和rAF的输出早于click的情况。

如果要避免这个延迟,可以用pointerdown或mousedown事件替代click,这类事件没有双击检测的延迟,但要注意它们的触发时机更早,可能会引发其他交互问题(比如鼠标按下后未松开就移动的场景)。

内容的提问来源于stack exchange,提问作者connexo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 22:50:03