深入理解 Total Blocking Time(TBT)

在前端性能优化中,Total Blocking Time (TBT) 是一个不容忽视的重要指标。它是衡量网页交互性能的关键指标之一,尤其对单页应用和动态内容页面尤为重要。本文将通过理论解析、代码示例以及优化策略,为您全面剖析 TBT 的本质和优化方法。


什么是 Total Blocking Time?

Total Blocking Time 表示从页面首次开始渲染内容到用户可交互之间,被阻塞时间的总和。具体来说,它计算的是 长任务(任务执行时间超过 50ms)阻塞主线程的时间

  • 核心概念

    • 浏览器主线程任务超过 50ms 的部分,会被认为是阻塞时间。
    • 这些阻塞时间累计起来,就形成了 TBT。

公式

ini 复制代码
TBT = ∑(每个任务耗时 - 50ms),仅计算超过 50ms 的任务

为什么 TBT 重要?

  • 用户体验:TBT 直接影响网页的交互体验,阻塞越多,用户感觉越"卡顿"。
  • Lighthouse 评分:TBT 是 Google Lighthouse 计算性能评分的重要组成部分。
  • 影响 FID(First Input Delay) :TBT 与用户首次交互的延迟密切相关。如果 TBT 长,用户输入可能被延迟处理。

如何测量 TBT?

  1. 使用 Lighthouse: 打开 Chrome DevTools,运行 Lighthouse 报告。在性能评分中,可以看到 TBT 的具体数值。

  2. 使用 WebPageTest: WebPageTest 也可以测量 TBT,并提供详细的阻塞任务分析。

  3. 使用 JavaScript 性能 API: 使用 Performance Observer 捕获长任务的执行时间:

    javascript 复制代码
    const observer = new PerformanceObserver((list) => {
        for (const entry of list.getEntries()) {
            if (entry.duration > 50) {
                console.log(`Long Task Detected: ${entry.duration}ms`);
            }
        }
    });
    
    observer.observe({ type: 'longtask', buffered: true });

TBT 的常见问题及代码示例

1. JavaScript 执行时间过长

  • 问题:JavaScript 阻塞主线程,导致用户无法进行操作。

  • 示例:

    javascript 复制代码
    // 一个耗时过长的同步任务
    function heavyTask() {
        const start = Date.now();
        while (Date.now() - start < 200) {
            // 模拟长任务
        }
    }
    heavyTask();
  • 优化方法: 将长任务拆分为小任务,通过 setTimeoutrequestIdleCallback 优化:

    scss 复制代码
    function heavyTaskOptimized() {
        let start = 0;
        const chunk = 20; // 每次处理 20ms
    
        function processChunk() {
            const now = Date.now();
            while (Date.now() - now < chunk) {
                // 模拟部分任务
                start++;
            }
    
            if (start < 1000) {
                setTimeout(processChunk, 0); // 将剩余任务推迟到下一个事件循环
            }
        }
        processChunk();
    }
    heavyTaskOptimized();

2. 过度渲染导致阻塞

  • 问题:频繁的 DOM 操作占用主线程。

  • 示例:

    ini 复制代码
    // 创建 1000 个 DOM 元素
    for (let i = 0; i < 1000; i++) {
        const div = document.createElement('div');
        div.textContent = `Element ${i}`;
        document.body.appendChild(div);
    }
  • 优化方法:使用 DocumentFragment 或虚拟 DOM 减少渲染阻塞:

    ini 复制代码
    const fragment = document.createDocumentFragment();
    for (let i = 0; i < 1000; i++) {
        const div = document.createElement('div');
        div.textContent = `Element ${i}`;
        fragment.appendChild(div);
    }
    document.body.appendChild(fragment);

3. 大量 CSS 计算和重绘

  • 问题:复杂的 CSS 样式或动画阻塞渲染。

  • 示例:

    css 复制代码
    .heavy-animation {
        animation: heavyTask 10s linear infinite;
    }
    
    @keyframes heavyTask {
        0% { transform: rotate(0deg); }
        100% { transform: rotate(360deg); }
    }
  • 优化方法:尽量使用 transformopacity,避免触发布局和重绘:

    css 复制代码
    .optimized-animation {
        animation: optimizedTask 10s linear infinite;
    }
    
    @keyframes optimizedTask {
        0% { transform: translateX(0); }
        100% { transform: translateX(100px); }
    }

优化 TBT 的最佳实践

  1. 减少长任务

    • 将耗时任务拆分为更小的片段。
    • 使用 requestIdleCallback 或 Web Workers 来异步执行任务。
  2. 延迟加载资源

    • 通过动态 import() 延迟加载非关键 JavaScript 模块。

    • 示例:

      ini 复制代码
      import('./heavy-module.js').then(module => {
          module.init();
      });
  3. 优化第三方脚本

    • 删除未使用的脚本,避免引入影响性能的广告或分析工具。
  4. 使用高效的数据处理

    • 使用流处理或增量渲染优化大数据处理。
  5. CSS 和动画优化

    • 使用 GPU 加速的 transformopacity,避免触发重排和重绘。

工具推荐

  1. Lighthouse: Google 官方提供的性能分析工具,可以生成全面的 TBT 报告。

  2. WebPageTest: 高级分析工具,适合测试复杂场景。

  3. Perfume.js: 一个前端性能监控工具,支持自动计算 TBT 和其他指标。

    javascript 复制代码
    import { Perfume } from 'perfume.js';
    const perfume = new Perfume({ firstPaint: true, timeToInteractive: true });
    console.log(`TBT: ${perfume.totalBlockingTime}`);

总结

TBT 是一个反映网页交互性能的重要指标,它不仅影响用户体验,还影响 SEO 和核心 Web 指标的评分。在现代 Web 开发中,通过优化 JavaScript 执行、减少阻塞操作和充分利用异步技术,可以显著降低 TBT 提升性能。

优化 TBT 的过程,既是对技术能力的考验,也是提升用户体验的关键一步。无论是小型项目还是复杂应用,专注于优化 TBT,都会为用户带来更流畅的使用体验。

相关推荐
roamingcode1 小时前
前端组件标准化专家Prompt指令的最佳实践
前端·prompt
LXY202305042 小时前
css三角图标
前端·javascript·css
spring_007_9992 小时前
在uniapp中修改打包路径
前端·uni-app
cheese-liang2 小时前
Excel中Address函数的用法
前端·excel
prince_zxill3 小时前
JavaScript 中的 CSS 与页面响应式设计
前端·javascript·css·前端框架·html
timerring3 小时前
Introduction to the HTTP and HTTPS Protocol
网络·http·https
林涧泣3 小时前
【Uniapp-Vue3】获取用户状态栏高度和胶囊按钮高度
前端·vue.js·uni-app
领秀58584 小时前
我问了DeepSeek和ChatGPT关于vue中包含几种watch的问题,它们是这么回答的……
前端·javascript·vue.js
prince_zxill4 小时前
使用 Postman 进行 API 测试:从入门到精通
javascript·网络·websocket·测试工具·postman
三原4 小时前
vue3实现可以拖动的弹窗组件, 做这个组件可以学习到什么?
前端·javascript·vue.js