单页应用如何提高加载速度

通过代码分割、缓存、预加载等技术优化 SPA 加载性能

问题

单页应用(SPA)首次加载时往往需要下载大量 JavaScript 和资源文件,如何优化加载速度?

解答

代码分割与懒加载

将应用代码拆分成多个小块,按需加载,避免一次性加载所有代码。

// React 示例
import { lazy, Suspense } from 'react';

const Dashboard = lazy(() => import('./Dashboard'));
const Profile = lazy(() => import('./Profile'));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Routes>
        <Route path="/dashboard" element={<Dashboard />} />
        <Route path="/profile" element={<Profile />} />
      </Routes>
    </Suspense>
  );
}

资源缓存

配置合理的缓存策略,让浏览器缓存静态资源。

// webpack 配置示例
module.exports = {
  output: {
    filename: '[name].[contenthash].js',
    clean: true
  }
};
# nginx 缓存配置
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
  expires 1y;
  add_header Cache-Control "public, immutable";
}

预加载关键资源

使用 preloadprefetch 提前加载关键资源。

<!-- 预加载关键 CSS 和字体 -->
<link rel="preload" href="/main.css" as="style">
<link rel="preload" href="/font.woff2" as="font" crossorigin>

<!-- 预获取可能需要的资源 -->
<link rel="prefetch" href="/dashboard.js">

图片优化

选择合适的图片格式并压缩,小图标使用字体图标或 SVG。

<!-- 使用 WebP 格式,提供降级方案 -->
<picture>
  <source srcset="image.webp" type="image/webp">
  <img src="image.jpg" alt="description">
</picture>

<!-- 响应式图片 -->
<img srcset="small.jpg 480w, medium.jpg 800w, large.jpg 1200w"
     sizes="(max-width: 600px) 480px, 800px"
     src="medium.jpg" alt="description">

启用压缩

在服务器端启用 Gzip 或 Brotli 压缩。

// Express 示例
const compression = require('compression');
app.use(compression());

使用 CDN

将静态资源部署到 CDN,加速全球访问。

// webpack 配置 CDN
module.exports = {
  output: {
    publicPath: 'https://cdn.example.com/assets/'
  }
};

优化 API 请求

减少请求数量,使用缓存和批量请求。

// 使用 SWR 缓存请求
import useSWR from 'swr';

function Profile() {
  const { data } = useSWR('/api/user', fetcher, {
    revalidateOnFocus: false,
    dedupingInterval: 60000
  });
  
  return <div>{data?.name}</div>;
}

// 批量请求
const [user, posts] = await Promise.all([
  fetch('/api/user'),
  fetch('/api/posts')
]);

服务器端渲染(SSR)

使用 SSR 生成首屏 HTML,减少客户端渲染时间。

// Next.js 示例
export async function getServerSideProps() {
  const data = await fetchData();
  return { props: { data } };
}

export default function Page({ data }) {
  return <div>{data.title}</div>;
}

关键点

  • 代码分割和路由懒加载可显著减少首次加载体积
  • 合理配置缓存策略(contenthash + 长期缓存)提高二次访问速度
  • 预加载关键资源和预获取可能访问的页面改善用户体验
  • 图片优化(WebP、压缩、响应式)和启用 Gzip/Brotli 压缩减少传输大小
  • SSR 适合首屏性能要求高的场景,但会增加服务器负担和架构复杂度