OpenPWAStore
返回 News
Guide · May 20, 2026

INP 是 PWA 安装信任中最重要的 Core Web Vitals 指标

用户不会安装感觉慢的应用。INP 衡量影响安装决策的真实响应能力。

OpenPWA Editorial2 min read
INP 是 PWA 安装信任中最重要的 Core Web Vitals 指标 cover

为什么在已安装的 PWA 中 INP 比 LCP 更重要

Largest Contentful Paint (LCP) 衡量加载速度。Interaction to Next Paint (INP) 衡量交互速度。对于已安装的 PWA,用户已经"支付"了加载成本——他们期望从那里获得快速响应。高 INP 分数会让应用感觉"坏了"或"低质量",直接影响安装保留率和口碑推荐。

根据 web.dev 的 Core Web Vitals 指南,INP 取代了 First Input Delay (FID) 作为响应性指标,因为 FID 仅衡量第一次交互——现在是一致的响应性。

INP 实际测量什么

INP 捕获最长的交互延迟,从:

  1. 用户点击/按钮按下
  2. 主线程开始处理
  3. 视觉反馈在屏幕上渲染

这包括所有三个阶段:

  • 输入延迟:用户操作时主线程被阻塞
  • 处理时间:事件处理程序、JavaScript 执行
  • 呈现延迟:浏览器渲染视觉变化

良好 INP:< 100ms 需改进:100ms - 200ms 差:> 200ms

为什么高 INP 破坏 PWA 信任

想想用户期望:

  • 原生应用:按钮点击 → 视觉反馈约 16ms(1 帧)
  • 慢 Web:按钮点击 → 加载转圈、延迟、渲染(~800ms)
  • 好 PWA:按钮点击 → 100ms 内反馈(接近原生感觉)

当用户安装"类原生"Web 应用时,他们潜意识中会以实际原生应用为基准。高 INP 让 PWA 感觉"廉价"或"坏了",导致:

  1. 立即卸载:"这真的不是原生应用"
  2. 差评:"慢"、"无响应"、"故障频发"
  3. 拒绝重装:"这个品牌的 Web 应用质量很差"

PWA 特定的 INP 陷阱

PWA 比普通 Web 页面有更高的 INP 风险:

| 风险因素 | 为什么 PWA 脆弱 | 修复 | |----------|-----------------|------| | 离线优先架构 | IndexedDB 读取可阻塞主线程 | 使用 IDB Keyval 模式或后台同步 | | Service Worker 生命周期 | 激活竞争条件延迟事件 | 预热 SW,回退到主线程 | | Manifest 截图生成 | 安装前渲染耗时 | 预生成,使用更简单格式 | | 大型 JavaScript 包 | 已安装应用缓存不完美 | 代码分割,延迟加载路由 | | 平台检测代码 | 每次交互都运行特性检查 | 在模块作用域缓存检测结果 |

PWA 的实用 INP 优化

1. 提前加载 JavaScript 执行

// 在安装按钮显示前
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js');
  // 缓存用户能力
  const supportsFileAPI = 'showOpenFilePicker' in window;
  const supportsClipboard = 'clipboard' in navigator;
}

2. 将昂贵工作安排在交互后

// 安装按钮处理程序(快!)
button.onclick = () => {
  // 立即反馈:显示加载转圈
  showLoadingSpinner();
  
  // 昂贵工作:帧后安排
  requestAnimationFrame(() => {
    setTimeout(async () => {
      await prewarmServiceWorker();
      await cacheOfflineAssets();
      await verifyInstallCriteria();
    }, 0);
  });
};

3. 避免布局抖动

// 坏:读-写-读-写模式
const height = el.clientHeight; // 强制布局
el.style.height = height + 10 + 'px';
const width = el.clientWidth; // 再次强制布局

// 好:批量读取,然后批量写入
const heights = elements.map(el => el.clientHeight);
elements.forEach((el, i) => {
  el.style.height = heights[i] + 10 + 'px';
});

4. 使用 Web Workers 处理繁重任务

// 不要阻塞主线程
const worker = new Worker('/offline-validator.js');
worker.postMessage({ action: 'validate-manifest' });
worker.onmessage = (event) => {
  if (event.data.valid) showInstallButton();
};

平台特定的 INP 行为

iOS Safari PWA

  • WebView 调度延迟更高(~20-30ms 基线)
  • IndexedDB 读取串行化,可阻塞主线程
  • 修复:小型读取使用 IndexedDB Keyval 模式

Android Chrome PWA

  • 较低基线延迟(~10-15ms)
  • V8 更好地优化热路径
  • 修复:将交互代码保留在主包中,避免热路径的动态导入

桌面 PWA

  • 鼠标 vs 触摸:鼠标约 8ms 延迟 vs 触摸约 30ms
  • 窗口调整大小事件可使 INP 尖峰
  • 修复:节流调整大小,使用 ResizeObserver 代替

测量工作流

Chrome DevTools Performance 面板:

  1. 加载你的 PWA
  2. 打开 Performance 面板
  3. 开始录制
  4. 点击按钮/交互 5-10 次
  5. 停止录制
  6. 查找 "INP" 指标或长任务(>50ms)

自动化测试:

// Lighthouse CI + INP 检查
await lighthouse('https://pwa.example.com', {
  onlyCategories: ['performance'],
  thresholds: {
    'interaction-to-next-paint': 100 // ms
  }
});

INP vs 其他指标:报告什么

| 指标 | 对于 PWA,如果... 专注于此 | |------|---------------------------| | INP | 用户点击、点按、表单提交 | | LCP | 首次加载、深度链接 | | CLS | 动态内容、动画、轮播 | | FID | 较旧浏览器(Chrome 95 及以下)|

什么时候"够好"就真的够好了

INP 目标取决于 PWA 类别:

  • 电商 PWA:目标 <100ms(用户放弃慢购物车)
  • 媒体 PWA:150ms 可接受(每次交互需求较少)
  • 工具 PWA:<200ms 可容忍(交互较少,更基于任务)
  • 社交 PWA:<80ms 理想(连续交互循环)

下一步

使用 DevTools 测量你 PWA 的当前 INP,然后使用 requestAnimationFrame + setTimeout 批处理将昂贵工作(service worker 预热、缓存预热)安排在用户交互之外。