前端性能优化:首字节时间与首屏时间

发布于:2024-10-12 ⋅ 阅读:(126) ⋅ 点赞:(0)

首字节时间和首屏时间的概念

首字节时间 (Time to First Byte, TTFB)
  • 定义: 首字节时间是指从客户端发起请求到接收到服务器响应的第一个字节的时间。
  • 影响因素:
    • 服务器响应时间
    • 网络延迟
    • 数据传输时间
首屏时间 (First Contentful Paint, FCP)
  • 定义: 首屏时间是指从客户端发起请求到页面首次呈现内容的时间。
  • 影响因素:
    • HTML 文件大小
    • CSS 和 JavaScript 文件大小
    • 图片和其他资源的加载时间
    • 页面渲染时间

首字节时间优化

服务器响应时间优化
  • CDN: 使用内容分发网络 (CDN) 来减少网络延迟。
  • 缓存: 启用 HTTP 缓存机制,减少重复请求。
  • 压缩: 对响应内容进行压缩,减少传输时间。

nginx

# Nginx 配置示例
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
# Apache 配置示例
<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE text/plain
  AddOutputFilterByType DEFLATE text/html
  AddOutputFilterByType DEFLATE text/xml
  AddOutputFilterByType DEFLATE text/css
  AddOutputFilterByType DEFLATE application/xml
  AddOutputFilterByType DEFLATE application/xhtml+xml
  AddOutputFilterByType DEFLATE application/rss+xml
  AddOutputFilterByType DEFLATE application/javascript
  AddOutputFilterByType DEFLATE application/x-javascript
</IfModule>
网络延迟优化
  • 选择合适的服务器位置: 将服务器部署在离用户最近的位置。
  • 使用 HTTP/2 或 HTTP/3: 利用多路复用等特性减少延迟。
数据传输时间优化
  • 减少文件大小: 压缩 HTML、CSS 和 JavaScript 文件。
  • 分块传输: 对大文件进行分块传输。

首屏时间优化

减少 HTML 文件大小
  • 压缩 HTML: 使用工具如 html-minifier 进行压缩。
  • 移除无用内容: 移除不必要的注释和空白字符。
const htmlmin = require('html-minifier');

const minifiedHTML = htmlmin.minify(html, {
  collapseWhitespace: true,
  removeComments: true,
  removeRedundantAttributes: true,
  useShortDoctype: true,
  removeEmptyAttributes: true,
  removeStyleLinkTypeAttributes: true,
  keepClosingSlash: true,
  minifyJS: true,
  minifyCSS: true,
  minifyURLs: true
});
减少 CSS 和 JavaScript 文件大小
  • 压缩 CSS: 使用工具如 cssnano 进行压缩。
  • 压缩 JavaScript: 使用工具如 uglify-js 进行压缩。
const cssnano = require('cssnano').default;

const minifiedCSS = cssnano.process(css, { from: undefined }).css;

const UglifyJS = require("uglify-es");
const minifiedJS = UglifyJS.minify(js).code;
图片和其他资源的优化
  • 压缩图片: 使用工具如 imagemin 进行压缩。
  • 使用 WebP 格式: WebP 格式通常比 JPEG 和 PNG 更小。
const imagemin = require('imagemin');
const imageminMozjpeg = require('imagemin-mozjpeg');
const imageminPngquant = require('imagemin-pngquant');

(async () => {
  const files = await imagemin(['images/*.{jpg,png}'], {
    destination: 'build/images',
    plugins: [
      imageminMozjpeg({ quality: 75 }),
      imageminPngquant({
        quality: [0.6, 0.8]
      })
    ]
  });
})();
页面渲染时间优化
  • 异步加载 CSS 和 JavaScript: 使用 async 和 defer 属性。
  • 使用 <link rel="preload">: 预加载关键资源。
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="styles.css">
  <script src="scripts.js" defer></script>
  <link rel="preload" href="images/logo.png" as="image">
</head>
<body>
  <h1>Hello World!</h1>
  <img src="images/logo.png" alt="Logo">
</body>
</html>

实战案例:优化一个简单的网站

原始代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    body {
      background-color: #f0f0f0;
      font-family: Arial, sans-serif;
    }
    h1 {
      color: blue;
    }
    img {
      width: 200px;
    }
  </style>
  <script>
    function sayHello() {
      console.log('Hello!');
    }
  </script>
</head>
<body>
  <h1>Hello World!</h1>
  <img src="images/logo.png" alt="Logo">
  <button onclick="sayHello()">Click me</button>
</body>
</html>
优化后的代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    body {background:#f0f0f0;font-family:Arial,sans-serif;}
    h1 {color:blue;}
    img {width:200px;}
  </style>
  <script>
    function sayHello(){console.log('Hello!');}
  </script>
  <link rel="preload" href="images/logo.png" as="image">
</head>
<body>
  <h1>Hello World!</h1>
  <img src="images/logo.png" alt="Logo">
  <button onclick="sayHello()">Click me</button>
</body>
</html>
服务器配置优化
server {
  listen 80;
  server_name example.com;

  gzip on;
  gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

  location / {
    root /var/www/html;
    index index.html;
  }

  location ~* \.(jpg|jpeg|png|gif|svg)$ {
    expires 30d;
    add_header Cache-Control "public";
  }
}

性能监控与测试

使用 Lighthouse
  • 安装 Lighthouse: 使用 Chrome DevTools 中的 Lighthouse 工具。
  • 运行性能测试: 分析性能瓶颈。
npm install -g lighthouse
lighthouse http://example.com --quiet
使用 WebPageTest
  • 在线测试: 使用 WebPageTest 在线测试工具。
  • 分析报告: 获取详细的性能报告。
wget https://www.webpagetest.org/runtest.php?url=http://example.com&f=html&k=public

服务器端优化

使用高性能服务器架构

  • Node.js: 利用 Node.js 的异步非阻塞 I/O 特性提高服务器响应速度。
  • Go: Go 语言具有优秀的并发性能,适合处理高并发请求。

优化数据库查询

  • 索引优化: 为常用查询字段添加索引。
  • 查询优化: 避免全表扫描,使用更高效的查询语句。
-- 添加索引
ALTER TABLE users ADD INDEX idx_email (email);

-- 优化查询
SELECT * FROM users WHERE email = 'example@example.com';

优化静态资源处理

  • 使用静态文件服务器: Nginx 或 Apache 作为静态文件服务器。
  • 缓存静态资源: 利用浏览器缓存静态资源。
server {
  listen 80;
  server_name example.com;

  gzip on;
  gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

  location /static/ {
    alias /var/www/static/;
    expires 30d;
    add_header Cache-Control "public";
  }

  location /api/ {
    proxy_pass http://backend;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
  }
}

首屏时间优化的进阶方法

减少资源加载时间

使用懒加载

  • 图片懒加载: 使用 loading=“lazy” 属性。
  • 脚本懒加载: 使用 async 和 defer 属性。
<img src="images/logo.png" alt="Logo" loading="lazy">

<script src="scripts.js" async></script>

使用 Service Worker

  • 缓存关键资源: 使用 Service Worker 缓存关键资源。
  • 离线访问: 提升用户体验,在离线情况下也能访问部分页面。
// service-worker.js
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open('v1').then(cache => {
      return cache.addAll([
        '/',
        '/index.html',
        '/styles.css',
        '/scripts.js',
        '/images/logo.png'
      ]);
    })
  );
});

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(response => {
      return response || fetch(event.request);
    })
  );
});
减少页面渲染时间

使用 Critical CSS

  • 提取关键样式: 提取首屏所需的关键样式。
  • 内联关键样式: 将关键样式内联到 HTML 中。
// critical-css.js
const critical = require('critical');

critical.generate({
  base: './',
  src: 'index.html',
  dest: 'critical.css',
  inline: true,
  extract: false,
  width: 1366,
  height: 768
});
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    /* 内联的关键样式 */
    body { background-color: #f0f0f0; font-family: Arial, sans-serif; }
    h1 { color: blue; }
    img { width: 200px; }
  </style>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <h1>Hello World!</h1>
  <img src="images/logo.png" alt="Logo">
  <button onclick="sayHello()">Click me</button>

  <script>
    function sayHello() {
      console.log('Hello!');
    }
  </script>
</body>
</html>

使用 Web Workers

  • 后台计算: 将复杂的计算任务放到 Web Workers 中执行。
  • 减少主线程负担: 提升页面渲染性能。
// main.js
const worker = new Worker('worker.js');

worker.onmessage = function(event) {
  console.log('Received:', event.data);
};

worker.postMessage({ action: 'calculate', data: [1, 2, 3] });
javascript
// worker.js
self.onmessage = function(event) {
  const { action, data } = event.data;

  if (action === 'calculate') {
    const result = data.reduce((acc, curr) => acc + curr, 0);
    postMessage(result);
  }
};

网站公告

今日签到

点亮在社区的每一天
去签到