Skip to content

好的,根据您提供的两篇关于 Next.js 缓存机制的文档,我为您总结如下:

Next.js 拥有一套强大且复杂的缓存体系,旨在优化性能和降低成本。这套体系包含四种主要的缓存机制,它们在不同的层面、不同的位置工作,共同协作。


一、 四种缓存机制概览

机制缓存内容存储位置主要目的持续时间
1. 请求记忆 (Request Memoization)函数返回值服务端内存在单个请求的 React 组件树渲染过程中,避免对同一数据的重复请求每个请求的生命周期
2. 数据缓存 (Data Cache)数据 (如 fetch 结果)服务端跨用户请求和部署复用数据,减少对数据源的访问持久,除非重新验证或退出
3. 完整路由缓存 (Full Route Cache)HTML 和 RSC Payload服务端复用整个路由的渲染结果,极大降低服务端渲染成本持久,跨部署后清除
4. 路由缓存 (Router Cache)RSC Payload客户端浏览器内存减少导航时的服务端请求,实现快速、无刷新的页面切换用户会话期间或基于时间(静态5分钟,动态30秒)

二、 详细解析

1. 请求记忆 (Request Memoization)

  • 本质:这是 React 的特性,而非 Next.js 特有。它通过“函数记忆”原理工作,对在同一个 React 组件树渲染过程中发起的、参数相同的 fetch 请求进行去重。
  • 作用域:仅在 React 组件树内有效(如 layout, page, generateMetadata 等)。
  • 持续时间:仅存在于一次服务器请求的整个渲染周期内。渲染结束后,缓存即被清除。
  • 退出方式:不建议退出。若必须,可使用 AbortController 创建不同的 signal 对象来“欺骗”缓存机制,使其认为是不同的请求。

2. 数据缓存 (Data Cache)

  • 本质:这是 Next.js 提供的持久化缓存,可以跨多个用户请求和应用部署共享数据。
  • 配置方式
    • fetch(url, { cache: 'force-cache' }): 强制缓存(默认行为)。
    • fetch(url, { cache: 'no-store' }): 强制不缓存,每次请求都从源获取。
    • fetch(url, { next: { revalidate: 3600 } }): 基于时间的重新验证,例如每3600秒(1小时)后,有新请求到来时会触发后台更新。
    • export const revalidate = 3600: 路由段配置,作用于该段内所有 fetch 请求。
  • 按需重新验证
    • 基于标签 (revalidateTag): 为 fetch 请求打上标签(next: { tags: ['news'] }),然后通过 revalidateTag('news') 来清除所有带此标签的缓存。
    • 基于路径 (revalidatePath): 通过 revalidatePath('/dashboard') 来清除特定路径相关的缓存。
  • 退出方式:使用 cache: 'no-store'dynamic = 'force-dynamic'

3. 完整路由缓存 (Full Route Cache)

  • 内容:缓存的是路由在构建时或首次请求时生成的最终产物——HTMLRSC Payload
  • 适用范围仅适用于静态渲染 (Static Rendering) 的路由。动态渲染的路由无法被完整路由缓存。
  • 持续时间:持久化存储在服务端。
  • 失效方式
    1. 重新验证数据:当路由依赖的数据缓存被重新验证并更新时,完整路由缓存也会随之失效并重建。
    2. 重新部署:每次应用重新部署,完整路由缓存都会被清除。
  • 退出方式:将路由转为动态渲染。方法包括:
    • 使用 dynamic = 'force-dynamic'revalidate = 0
    • 路由中包含 no-storefetch 请求。
    • 使用 cookiesheaders 等动态函数。

4. 路由缓存 (Router Cache)

  • 本质:客户端的内存缓存,存储的是从服务端获取的 RSC Payload
  • 工作原理:当用户通过 <Link> 导航时,Next.js 会预获取目标路由的 RSC Payload 并存入此缓存。再次访问时,直接从缓存中读取,无需网络请求,实现瞬时跳转。
  • 持续时间
    • 静态路由:缓存5分钟。
    • 动态路由:缓存30秒。
    • 页面刷新后,缓存会被清除。
  • 失效方式
    • 调用 router.refresh()
    • 在 Server Actions 中调用 revalidatePathrevalidateTag
    • 在 Server Actions 中修改 cookies
  • 重要提示无法完全退出。即使将 <Link prefetch={false}>,访问过的路由仍会临时缓存30秒以支持嵌套路由的即时导航。

三、 关键区别与实战要点

  • 请求记忆 vs 数据缓存

    • 请求记忆是单次请求内的“去重”,是 React 的优化。
    • 数据缓存是跨请求的“持久化”,是 Next.js 的核心功能。
    • 两者通常同时存在。实战中,即使关闭了数据缓存,请求记忆仍可能导致多次调用返回相同数据。
  • 完整路由缓存 vs 路由缓存

    • 完整路由缓存服务端,针对静态路由,缓存的是HTML + RSC Payload
    • 路由缓存客户端,针对所有路由(静/动),缓存的是RSC Payload
  • 开发痛点:路由缓存是“双刃剑”。它提供了丝滑的用户体验,但也常导致数据不更新(如导航后时间未变)。开发者必须理解其存在,并在需要实时数据时,通过 router.refresh() 或修改 cookies 等方式主动使其失效。

  • API 与缓存关系:文档末尾的表格是解决缓存问题的“万能钥匙”。当遇到数据未更新时,应先回顾使用了哪些 API,然后根据表格判断影响了哪种缓存,再选择对应的重新验证或退出策略。


总结:Next.js 的缓存机制设计精妙,自动化程度高。理解这四种缓存的层级、作用域和生命周期,是高效开发和调试 Next.js 应用的关键。开发者应善用缓存提升性能,同时也要掌握控制缓存的“开关”和“扳手”,以应对数据实时性等复杂场景。