FID 必须用 PerformanceObserver 监听 first-input 事件获取,因手动监听无法捕获浏览器任务队列中的输入处理延迟;需早期注册、过滤伪事件、校验 entry 字段,并按设备与分位数分析分布。

FID 不能靠手动计时或事件监听模拟,必须用 PerformanceObserver 监听 first-input 类型事件——这是唯一能准确拿到浏览器内部输入处理延迟的方式。
为什么 addEventListener('click') 拿不到真正的 FID
手动监听 click 或 keydown 只能捕获事件触发时间,但 FID 的定义是“用户首次输入到浏览器实际开始处理该输入之间的时间差”,这个差值藏在浏览器任务队列调度里,JS 主线程无法直接观测。常见错误包括:
- 用
performance.now()在事件回调开头打点,结果把 JS 执行耗时也混进去了 - 在 SPA 路由切换后重新绑定监听,漏掉首屏可交互前的点击(比如加载中用户猛点按钮)
- 没过滤掉
input类型为focus、blur的伪输入事件,导致误报
PerformanceObserver 初始化必须在页面早期执行
监听器注册太晚会丢失首屏前的 first-input 事件——浏览器一旦触发并完成该事件的处理,就不会再补发。实操建议:
- 脚本需内联或设
async,避免等DOMContentLoaded再初始化 - 注册后立即调用
observer.takeRecords(),捕获已触发但尚未派发的记录(尤其对快速交互场景有效) - 只监听
first-input,不要和layout-shift或navigation混在一个 observer 里,避免干扰或遗漏
从 entry 中提取合规的 FID 值
first-input 类型的 PerformanceEntry 包含 startTime 和 processingStart,二者之差才是标准 FID。注意以下边界:
-
entry.duration是废弃字段,不要用 - 必须校验
entry.name === 'first-input',部分旧版 Chrome 会返回navigation类型的伪造 entry - 移动端常出现
inputType: 'pointerdown',它合法;但'focus'不算真实用户意图输入,应跳过 - 若
processingStart - startTime < 0,说明数据异常,直接丢弃(极少数低版本 Safari 存在)
上报与体验量化要区分设备与分位数
FID 的业务意义不在单次值,而在分布。例如:
- 移动端第 75 百分位超过 300ms,说明 1/4 用户已感知卡顿
- 桌面端第 90 百分位仍低于 100ms,可判定首屏交互体验达标
- 不要聚合所有 FID 做平均值——一个 2000ms 的坏样本会拉高均值,掩盖多数用户的真实体验
容易被忽略的是:微前端场景下,子应用可能覆盖主应用的 PerformanceObserver 实例,导致 FID 只记录主应用生命周期内的输入。必须确保每个微应用独立注册、独立上报,并带上 app-id 上下文标签。

















