静态渲染与动态渲染

在上一章节中,您为仪表盘概览页面获取了数据。但我们简要讨论了当前设置的两个局限性:

  1. 数据请求形成了意料之外的瀑布流
  2. 仪表盘是静态的,任何数据更新都不会反映在应用中

什么是静态渲染?

通过静态渲染,数据获取和渲染会在构建时(部署时)或重新验证数据时在服务端完成。

当用户访问您的应用时,会直接返回缓存结果。静态渲染具有以下优势:

  • 更快的网站速度 - 预渲染内容可以缓存,并部署到 Vercel 等平台实现全球分发。这确保全球用户都能更快更可靠地访问您的内容
  • 减轻服务器负载 - 由于内容已被缓存,服务器无需为每个用户请求动态生成内容,从而降低计算成本
  • SEO 优化 - 预渲染内容更易于搜索引擎爬虫索引,因为页面加载时内容已就绪,有助于提升搜索排名

静态渲染适用于无数据用户间共享数据的 UI,如静态博客或产品页面。但对于需要展示个性化数据且频繁更新的仪表盘可能不太适合。

静态渲染的对立面是动态渲染。

什么是动态渲染?

通过动态渲染,内容会在请求时(用户访问页面时)为每个用户在服务端实时渲染。动态渲染具有以下优势:

  • 实时数据 - 可展示实时或频繁更新的数据,非常适合数据变化频繁的场景
  • 用户专属内容 - 更容易提供个性化内容(如仪表盘或用户资料),并根据用户交互更新数据
  • 请求时信息获取 - 可以访问仅在请求时才能获取的信息,如 cookies 或 URL 搜索参数

模拟慢速数据请求

我们正在构建的仪表盘应用是动态的。

但上一章提到的问题仍然存在:如果某个数据请求比其他请求慢会发生什么?

让我们模拟慢速数据获取。在 app/lib/data.ts 中,取消 fetchRevenue() 函数内的 console.logsetTimeout 注释:

/app/lib/data.ts
export async function fetchRevenue() {
  try {
    // 为了演示效果人为延迟响应
    // 生产环境请勿这样做 :)
    console.log('正在获取营收数据...');
    await new Promise((resolve) => setTimeout(resolve, 3000));
 
    const data = await sql<Revenue[]>`SELECT * FROM revenue`;
 
    console.log('数据获取完成,耗时3秒');
 
    return data;
  } catch (error) {
    console.error('数据库错误:', error);
    throw new Error('获取营收数据失败');
  }
}

现在在新标签页打开 http://localhost:3000/dashboard/,注意页面加载时间变长。终端中您会看到以下信息:

正在获取营收数据...
数据获取完成,耗时3秒

这里我们添加了人为的3秒延迟来模拟慢速数据请求。结果是当数据获取时,整个页面的UI都会对访问者保持阻塞状态。这引出了开发者需要解决的常见问题:

在动态渲染中,应用的性能取决于最慢的数据请求速度。

On this page