TTI 时间太长,怎么优化首屏交互延迟?

萌新.莉莉 阅读 14

我们首页加载完 HTML 和关键 CSS 后,用户点击按钮没反应,得等好几秒才可交互。Lighthouse 报 TTI(Time to Interactive)高达 6s+,但 FCP 已经在 1.2s 就完成了。

我试过把非关键 JS 拆包并用 defer 加载,还把一些初始化逻辑放到了 requestIdleCallback 里,但 TTI 还是下不来。是不是还有别的主线程任务卡住了?比如这段初始化代码:

document.addEventListener('DOMContentLoaded', () => {
  initAnalytics();
  setupEventListeners();
  loadThirdPartyWidgets(); // 这个可能比较重
});

有没有办法精准定位是哪个任务拖慢了 TTI?或者该怎么拆分这些逻辑才能让页面更快可交互?

我来解答 赞 3 收藏
二维码
手机扫码查看
1 条解答
司徒洋博
这个问题很典型,FCP 跑赢了但 TTI 拉胯,基本就是 DOMContentLoaded 之后那些同步代码把主线程堵死了。

先说定位方法。你需要打开 Chrome DevTools,Performance 面板,点击 Record,然后刷新页面。等 TTI 之后停止录制,看 Main 线程的时间线。那些超过 50ms 的 Long Tasks 就是罪魁祸首,会看到一个一个的红色长条。找到那个时间段,看具体是什么函数在执行。

或者更精准的方式是在代码里埋点:

// 在关键节点打标记
performance.mark('init-start');
initAnalytics();
performance.mark('init-analytics-end');

performance.mark('widgets-start');
loadThirdPartyWidgets();
performance.mark('widgets-end');

// 然后在控制台看
performance.measure('analytics', 'init-start', 'init-analytics-end');
performance.measure('widgets', 'widgets-start', 'widgets-end');


这样 Performance 面板里就能看到每个阶段具体花了多长时间。

你那段代码的问题在于 DOMContentLoaded 触发后,三个函数是串行同步执行的,哪个慢就直接卡死交互。loadThirdPartyWidgets 既然标注了比较重,更可能是它的问题。

改造思路是这样的:

document.addEventListener('DOMContentLoaded', () => {
// 立即执行,不阻塞
initAnalytics();
setupEventListeners();

// 重的逻辑拆出去
if ('requestIdleCallback' in window) {
requestIdleCallback(() => loadThirdPartyWidgets());
} else {
setTimeout(() => loadThirdPartyWidgets(), 2000);
}
});


但更推荐用动态 import 把第三方组件懒加载:

document.addEventListener('DOMContentLoaded', () => {
initAnalytics();
setupEventListeners();

// 用户可能需要交互的时候再加载
const loadWidgets = () => {
import('./third-party-widgets.js').then(module => {
module.init();
});
};

// 或者用 IntersectionObserver 等到可视区域再加载
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
loadWidgets();
observer.disconnect();
}
});
});

// 假设 widgets 在某个容器里
const widgetContainer = document.querySelector('#third-party-container');
if (widgetContainer) observer.observe(widgetContainer);
});


还有个关键点,很多第三方脚本本身就算 defer 了也照样阻塞。它们内部可能有同步的 DOM 操作或者大量计算。这种情况下可以考虑用 iframe 隔离,或者直接找第三方协商优化。

最后提一下,Chrome 的 Coverage 面板也能帮你看看首屏加载的 JS 里有多少其实根本没用到,那些无用的代码反而在增加解析时间。
点赞
2026-03-13 18:00