2025年从 SSR\SSG\ISR 到Nextjs 常见面题🤔

396 阅读9分钟

2025最新前端高频面筋| Vue篇

2025最新面筋| 408篇

2025前端最新高频面筋| React 篇

本篇以知识点讲解为主,分享出来也希望能帮助到有需要的朋友。针对面试,可以直接跳到文末,一起来讨论学习呀。Trae

写作思路:先提下 SSR\SSG\ISR,再指出lighthouse 性能测试工具,接下来是最近看到的Nextjs 常见面题个人解答。

小白先可以转# Nextjs 15 踩坑入门系列专栏

一、渲染策略对性能的影响

不同的渲染方式,会直接影响用户首次看到页面内容的速度、SEO 友好度以及服务器压力。我们主要关注三种模式:

1. 服务端渲染(SSR)

原理

  • 服务器在收到请求后,先运行应用逻辑,生成完整的 HTML 页面。
  • 浏览器拿到 HTML 后立刻渲染,给用户快速可视内容。
  • 随后客户端执行 JavaScript,所谓“水合”(Hydration),激活页面上的交互。

Next.js 示例

// pages/ssr-example.js
export async function getServerSideProps() {
  const res = await fetch('https://api.example.com/data');
  const data = await res.json();
  return { props: { data } };
}
function Page({ data }) {
  return (
    <ul>
      {data.map(item => <li key={item.id}>{item.name}</li>)}
    </ul>
  );
}
export default Page;

优缺点

  • 优点:每次请求都能拿到最新数据;SEO 支持好;适合需要用户个性化或认证态的场景。
  • 缺点:服务器压力大;首屏渲染虽快,但整体延迟受网络和后端性能影响。

2. 静态站点生成(SSG)

原理

  • 在构建时(npm run build),Next.js 预先跑完所有页面,生成静态 HTML 文件。
  • 用户每次访问都直接获取这些预构建文件,速度极快。
  • 依旧需要 “水合” 来激活交互逻辑。

Next.js 示例

// pages/ssg-example.js
export async function getStaticProps() {
  const res = await fetch('https://api.example.com/data');
  const data = await res.json();
  return { props: { data }, revalidate: 60 };
}
export default function Page({ data }) {
  return <h1>{data.title}</h1>;
}

优缺点

  • 优点:首屏加载最快;服务器压力最低;适合内容变化不频繁的博客、营销页等。
  • 缺点:构建时间随页面数量线性增长;动态内容或最新数据获取不实时。

3. 增量静态再生(ISR)

原理:在 SSG 的基础上,给页面设置 revalidate,让它在一定时间后自动后台更新,无需整站重构。

// pages/isr-example.js
export async function getStaticProps() {
  const res = await fetch('https://api.example.com/data');
  const data = await res.json();
  return { props: { data }, revalidate: 60 };
}
export default function Page({ data }) {
  return <p>更新时间:{new Date().toLocaleTimeString()}</p>;
}

优缺点

  • 优点:兼顾了 SSG 的性能和数据的时效性;构建速度更可控;适合大量动态页面但不需要秒级更新的场景。
  • 缺点:实现更复杂,缓存失效前用户可能看到旧数据。

渲染方式选型指南

  • SSR:当页面需要每次访问都拿最新数据、内容强依赖用户或地域信息时选它。
  • SSG:静态内容多、更新频率低、对首页加载速度有极高要求时用它。
  • ISR:页面数量大、需要定时更新但不必实时、又想保持高性能,就交给它。

二、前端性能监控的核心指标

我们可以按照lighthouse 插件,查看性能评估。

image.png

浏览器提供了 performance API,可以用来收集绝大多数我们关心的性能指标。

2.1 获取 Timing 信息

在控制台执行:

performance.getEntriesByType('navigation')[0]

你会看到一大堆时间戳,代表了不同阶段的开始与结束:

image.png
指标含义
navigationStart浏览器准备发起文档请求的时刻
fetchStart开始请求页面资源(DNS 解析前)的时间
domainLookupStart/EndDNS 解析开始/结束
connectStart/EndTCP/HTTPS 连接开始/结束
requestStart发起 HTTP 请求的时间
responseStart/End服务器响应首字节/所有字节到达的时间
domInteractiveDOM 解析完成,DOM 可操作的时间
domComplete文档及所有子资源加载完毕的时间
loadEventStart/Endload 事件触发开始/结束的时间

2.2 用户关注的关键指标

  • FCP(First Contentful Paint) :首次内容绘制,网页开始渲染第一个文本、图片或 SVG 的时间。可以用:

    performance.getEntriesByName('first-contentful-paint')[0].startTime
    
  • LCP(Largest Contentful Paint) :最大内容绘制,指页面可视区域内最大图片或文本块渲染完成的时间。推荐用 PerformanceObserver 监控。

  • TTI(Time to Interactive) :首批可交互时间,页面有大部分内容渲染完且能响应用户输入的时间。

  • 其他自定义指标

    • 网络响应时间 = responseStart - fetchStart
    • DOM 准备就绪时间 = domInteractive - fetchStart
    • 总加载核心时间 = domComplete - fetchStart

四、Next.js 常见面试考察

4.1 Next.js 水合原理

Hydration(水合)是客户端将服务端渲染出的静态 HTML 与 React 组件的事件处理程序绑定在一起的过程。服务端先生成完整的 HTML 结构,浏览器渲染后再下载并执行对应的 JavaScript,遍历 DOM,将事件监听器、状态管理逻辑附着到已有节点上,使页面从静态内容变为可交互状态。

4.2 SSR 与 SSG 的区别

  • SSR:SSR 是指在服务器端执行 React 逻辑,动态生成 HTML 内容,然后将生成的 HTML 发送到客户端。每次用户请求页面时,服务器都会重新渲染页面。
  • SSR 对seo友好,能够实现实时更新数据,能够根据用户请求(查询参数、用户身份等)动态生成内容。缺点也很明显,每次请求服务器都要重新渲染页面,对服务器性能要求高,并且每次服务器动态生成html,导致首屏加载速度慢。
  • SSG:SSG 是指在构建时一次性生成所有页面的静态 HTML 文件,后续请求直接返回这些静态文件。页面内容在构建时就已经确定,不会根据用户请求动态变化。
  • SSG和SSR有很相反性:SSG 页面是预先生成的静态html,所以首屏加载速度极快,而服务器又不用每次动态渲染页面,减少了服务器的负担。缺点尼,数据更新也就不及时,每次内容更新后需要重新构建和部署,不适用于动态内容,因为没法更加用户请求动态生成内容。
  • SSR 使用于新闻、电商网站,社交平台;而SSG 可扩展性好,适合大规模静态内容网站,如博客,文档网站。

4.3 App Router 与 Page Router 的区别

  • App Router(基于 React Server Components):页面拆分为 Server Component 和 Client Component,支持渐进式渲染和局部刷新,减少客户端负载。
  • (渐进式渲染:先加载server component内容,再按需加载client component)
  • Page Router(Pages 目录):经典的请求驱动路由,使用 getServerSidePropsgetStaticProps 等 API,在请求时或构建时生成完整页面。这与早期nextjs 项目兼容性好,适用于小型项目,使用起来直观,但是不支持渐进式加载和局部更新,对大型项目页面加载过重性能受到影响。

4.4 RSC 与 SSR 的差异及水合影响

  • RSC(React Server Components) :组件在服务器渲染后发送给客户端的是序列化的组件树,客户端仅在需要交互的部分进行 Hydration,而不是整个页面,都不需要为每个组件绑定事件,减少了 Hydration 负担。
  • SSR:服务器直接渲染完整 HTML,客户端必须对整个页面进行 Hydration,开销更大。

4.5 Next.js 路由缓存机制

  • 缓存内容:对于使用 App Router 的 RSC 路由,Next.js 会缓存已加载的组件树和数据,以便快速进行客户端导航。
  • 水合变化:缓存路由后切换时,仅重 Hydrate 新页面中未缓存的部分,其它部分复用已有绑定,提升首交互性能。

现在,我来讲一个具体的 Next.js 示例:

假设你有一个电商网站,用 Next.js App Router 搭建,包含首页、产品页和博客页。用户访问首页(/)时,会加载首页的组件和数据(比如推荐商品)。这些都被缓存起来。

当用户点击某个商品链接跳转到产品页(/products/123)时:

缓存内容

  • Next.js 会把产品页的组件(产品展示区、评论区等)和相关数据(产品详情、价格等)缓存起来。
  • 静态资源(比如产品图片)也会被缓存。

水合变化

  • 如果用户返回首页,Next.js 不会重新加载首页的所有内容。它会复用之前缓存的首页组件和数据。
  • 只有新变化的部分(比如用户可能添加了新评论)才会重新水合。

再比如,如果某个产品价格变化了,缓存会失效并更新:

缓存失效与更新

  • 产品页的缓存会自动失效(因为数据变化了)。
  • 下次用户访问产品页时,会获取更新后的价格信息并更新缓存。

4.6 异步组件加载处理

Next.js 利用 React.lazy 和 next/dynamic 在客户端按需加载组件:

  1. 初始页面只加载核心包和必要组件。可以使用React 的 React.lazySuspense。或 使用 Next.js 的 next/dynamic
  2. 遇到动态导入时,显示 loading 占位,后台下载对应 JS。
  3. 下载完成后执行 Yarn(或其他包管理工具)安装依赖,再对组件进行水合(Hydrate),使其变得可交互。

4.7 Diff 算法与直接操作 DOM 的性能对比

  • Diff(虚拟 DOM 比较) :比如,以react为例子。React 在内存中维护一个虚拟 DOM 树。当状态更新时,React 会生成一个新的虚拟 DOM 树,并与旧的虚拟 DOM 树进行比较(Diff)。Diff 算法会找出最小的变更集合,并将这些变更批量应用到真实 DOM 中。
  • 直接操作 DOM:直接使用原生 JavaScript 操作 DOM,例如 document.getElementByIdelement.innerHTML 等。每次更新都会触发重排和重绘,开销更大,而且难以管理
  • 结论:使用 Diff 算法在大多数复杂 UI 更新场景下性能更优。

4.8 Next.js 首页性能优化建议(从框架角度)

  1. 减少 Hydration 范围:将静态内容(如纯文本、图片等)无交互区域拆分为纯 Server Component,这样客户只需要对需要交互部分进行水合。
  2. 开启 RSC 和 Streaming:利用流式响应让用户更快看到内容。像使用app router 组件方式,RSC 会将页面内容分段发送到客户端,客户端可以逐步渲染内容。
  3. 动态导入大体量组件:使用 next/dynamic 动态导入大体量组件,减少初始加载提交,这时候可以配合自定义 loading,优化用户体验。
  4. 使用 CDN 缓存静态资源,配置next.config.js 指定今天资源cdn地址,使用cdn 缓存机制加载资源。 如果有图片,可以使用 next/image 组件自动实现图片懒加载(lazy load)和格式化。
  5. 分析 Bundle:通过 next build --profile 查找大体积包并拆分。