首页加载速度优化

要说面试的时候问到最多的问题,那性能优化绝对是躲不开的话题,基本每个公司面试我都遇到了相关问题,其中,首页加载速度优化又是其中最常问的问题,网上的文章比较零零散散,没有一个总结到十分满意的,于是自己便来总结一下

这张图是我发现的比较宝藏,比较全面的一张首页加载优化图,便以此图来进行相关总结

目录

一. 资源加载优化

  1. 压缩资源
  2. 启用Gzip压缩
  3. 使用缓存
  4. [使用内容分发网络 (CDN)](#使用内容分发网络 (CDN) "#%E4%BD%BF%E7%94%A8%E5%86%85%E5%AE%B9%E5%88%86%E5%8F%91%E7%BD%91%E7%BB%9C-cdn")
  5. 使用HTTP/2
  6. 优化DNS解析
  7. 减少HTTP请求数
  8. 预加载和预获取
  9. 使用更高效的图片格式
  10. 图片懒加载和路由懒加载

二. 页面渲染优化

  1. 优化CSS
  2. 使用CSS3动画代替JavaScript动画
  3. 将JavaScript放在页面底部
  4. 使用async和defer属性
  5. 减少和优化DOM操作
  6. [使用Virtual DOM](#使用Virtual DOM "#%E4%BD%BF%E7%94%A8virtual-dom")
  7. 避免布局抖动
  8. 使用will-change提示浏览器优化
  9. [使用服务端渲染 (SSR)](#使用服务端渲染 (SSR) "#%E4%BD%BF%E7%94%A8%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%B8%B2%E6%9F%93-ssr")
  10. 延迟加载资源

资源加载优化

压缩资源

通过 Webpack 配置,可以自动压缩 HTML、CSS 和 JavaScript 文件。

javascript 复制代码
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = {
    mode: 'production',
    entry: './src/index.js',
    output: {
        filename: 'bundle.js',
        path: __dirname + '/dist'
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [MiniCssExtractPlugin.loader, 'css-loader']
            }
        ]
    },
    optimization: {
        minimize: true,
        minimizer: [
            new TerserPlugin(),
            new CssMinimizerPlugin()
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            minify: {
                collapseWhitespace: true,
                removeComments: true,
                removeRedundantAttributes: true,
                useShortDoctype: true
            }
        }),
        new MiniCssExtractPlugin({
            filename: 'styles.css'
        })
    ]
};

启用Gzip压缩

通过 Webpack 配置,可以生成 Gzip 压缩文件。

js 复制代码
//在请求时会带上该请求头,声明它支持的压缩算法
Accept-Encoding: gzip, deflate, br
javascript 复制代码
// webpack.config.js
const CompressionPlugin = require('compression-webpack-plugin');

module.exports = {
    // 其他配置...
    plugins: [
        new CompressionPlugin({
            filename: '[path][base].gz',
            algorithm: 'gzip',
            test: /\.(js|css|html|svg)$/,
            threshold: 10240,
            minRatio: 0.8
        })
    ]
};

使用缓存

服务端通过配置协商缓存和强缓存,来实现请求的缓存,这里以强缓存为例

javascript 复制代码
// 设置强缓存
const express = require('express');
const path = require('path');

const app = express();

// 强缓存中间件
app.use((req, res, next) => {
    const options = {
        maxAge: '1y', // 缓存一年
        immutable: true
    };

    // 设置 Cache-Control 头
    res.set('Cache-Control', `public, max-age=${options.maxAge}, immutable`);
    next();
});

// 将静态文件托管到 public 目录
app.use(express.static(path.join(__dirname, 'public'), {
    maxAge: '1y' // 缓存一年
}));

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});

使用内容分发网络 (CDN)

通过 Webpack 配置,将静态资源路径指向 CDN。

javascript 复制代码
output: { 
filename: '[name].[contenthash].js',
path: __dirname + '/dist',
publicPath: 'https://cdn.example.com/' // 指向你的 CDN 地址 
},

使用HTTP/2

启用 HTTP/2 需要在服务器配置中完成,Webpack 本身不直接支持 HTTP/2 配置。

http 复制代码
# Nginx 配置
server {
    listen 443 ssl http2;
    server_name example.com;
    # SSL 配置
}

优化DNS解析

在 HTML 中添加 DNS 预获取。

html 复制代码
<link rel="dns-prefetch" href="//example.com">

减少HTTP请求数

通过 Webpack 配置,合并文件和使用图片精灵,同时我们可以将一些小图片转为base64格式(虽然会减少请求,但是转为base64资源体积会变大一点,所有不推荐进行大图片base64处理)

javascript 复制代码
// webpack.config.js
const SpriteLoaderPlugin = require('svg-sprite-loader/plugin');

module.exports = {
    // 其他配置...
    module: {
        rules: [
            {
                test: /\.svg$/,
                use: ['svg-sprite-loader']
            }
        ]
    },
    plugins: [
        new SpriteLoaderPlugin()
    ]
};

预加载和预获取

使用 Webpack 插件进行预加载和预获取。

javascript 复制代码
// webpack.config.js
const PreloadWebpackPlugin = require('preload-webpack-plugin');

module.exports = {
    // 其他配置...
    plugins: [
        new PreloadWebpackPlugin({
            rel: 'preload',
            as: 'script',
            include: 'allChunks'
        })
    ]
};

使用更高效的图片格式

通过 Webpack 配置,使用现代图片格式,如 WebP(但是得注意浏览器兼容性)。

javascript 复制代码
// webpack.config.js
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');

module.exports = {
    // 其他配置...
    module: {
        rules: [
            {
                test: /\.(jpe?g|png|gif|svg)$/i,
                type: 'asset',
                use: [
                    {
                        loader: ImageMinimizerPlugin.loader,
                        options: {
                            minimizerOptions: {
                                plugins: [
                                    ['imagemin-webp', { quality: 75 }]
                                ]
                            }
                        }
                    }
                ]
            }
        ]
    }
};

图片懒加载和路由懒加载

通过IntersectionObserver API和自定义指令来实现图片懒加载,路由懒加载即用vue的动态路由@import引入即可

javascript 复制代码
export default {
    inserted(el) {
        const loadImage = () => {
            const imageElement = el.tagName === 'IMG' ? el : el.querySelector('img');
            
            if (imageElement) {
                imageElement.src = imageElement.dataset.src;
                imageElement.onload = () => el.classList.add('loaded');
            }
        };

        const handleIntersect = (entries, observer) => {
            entries.forEach(entry => {
                if (entry.isIntersecting) {
                    loadImage();
                    observer.unobserve(el);
                }
            });
        };

        const options = {
            root: null,
            threshold: 0.1
        };

        const observer = new IntersectionObserver(handleIntersect, options);
        observer.observe(el);
    }
};

页面渲染优化

优化CSS

将 CSS 外链放在页面顶部,因为这样可以确保页面在加载时尽快应用样式,从而避免样式闪烁(FOUC,Flash of Unstyled Content)并提升用户体验。

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Example Page</title>
    <!-- 将 CSS 外链放在页面顶部 -->
    <link rel="stylesheet" href="styles/main.css">
    <link rel="stylesheet" href="styles/theme.css">
</head>
</html>

使用CSS3动画代替JavaScript动画

使用 CSS3 动画而不是 JavaScript 动画(原理: transform等css3属于是独立的图层,不会影响其他图层,而且使用GPU加速),以减少重排和重绘。

css 复制代码
.box {
    transition: transform 0.5s, opacity 0.5s;
}

.box:hover {
    transform: translateX(100px);
    opacity: 0.5;
}

将JavaScript放在页面底部

将 JavaScript 文件放在 <body> 标签的底部(现代浏览器支持async和defer后就不需要了)

html 复制代码
<body>
    <!-- Content -->
    <script src="bundle.js"></script>
</body>

使用async和defer属性

使用 asyncdefer 属性加载外部 JavaScript 文件。

html 复制代码
<script src="bundle.js" async></script>
<!-- 或者 -->
<script src="bundle.js" defer></script>

减少和优化DOM操作

减少不必要的 DOM 操作,合并多次操作为一次。

javascript 复制代码
// Before
element.style.width = '100px';
element.style.height = '100px';

// After
element.style.cssText = 'width: 100px; height: 100px;';

使用Virtual DOM

使用虚拟 DOM 技术(如 React)减少直接操作 DOM 带来的开销。

javascript 复制代码
// 使用 React 示例
import React, { useState } from 'react';

function App() {
    const [count, setCount] = useState(0);

    return (
        <div>
            <p>{count}</p>
            <button onClick={() => setCount(count + 1)}>Increment</button>
        </div>
    );
}

避免布局抖动

在操作 DOM 和样式时,避免可能导致重排的操作,对样式进行统一处理

javascript 复制代码
// Before
element.style.margin = '10px';
element.style.padding = '20px';
element.style.border = '1px solid #000';

// After
element.style.cssText = 'margin: 10px; padding: 20px; border: 1px solid #000;';

使用will-change提示浏览器优化

使用 will-change 属性可以提示浏览器即将发生的变化,使浏览器提前进行优化。

css 复制代码
.box {
    will-change: transform, opacity;
}

使用服务端渲染 (SSR)

使用服务端渲染技术提前生成 HTML 内容,减少客户端渲染的负担。

javascript 复制代码
// 使用 Next.js 进行 SSR 示例
import React from 'react';
import { renderToString } from 'react-dom/server';
import App from './App';

const html = renderToString(<App />);

延迟加载资源

延迟加载图片和非关键 CSS、JavaScript 文件。

html 复制代码
<img src="image.jpg" loading="lazy" alt="Lazy loaded image">

<script>
    var link = document.createElement('link');
    link.rel = 'stylesheet';
    link.href = 'non-critical-styles.css';
    document.head.appendChild(link);
</script>
相关推荐
牛奶4 分钟前
开发者的"奇技淫巧":那些让你效率翻倍的实战技巧
前端·后端·程序员
咸鱼翻身更入味4 分钟前
Vue创建一个简单的Agent聊天——工具调用
前端
Timo来了5 分钟前
indexDB的用法示例
前端
walking9578 分钟前
重新学习前端之设计模式与架构
前端·javascript·面试
walking95711 分钟前
重新学习前端之TypeScript
前端·javascript·面试
walking95711 分钟前
重新学习前端之Linux
前端·vue.js·面试
walking95712 分钟前
重新学习前端之CSS
前端·vue.js·面试
walking95712 分钟前
重新学习前端之Git
前端·vue.js·面试
walking95712 分钟前
重新学习前端之小程序
前端
魔术师Grace14 分钟前
AI让我退化成原始人了
前端·程序员