You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js unstable_cache未按预期工作问题求助

问题描述

我无法正确使用unstable_cache。我想缓存那些极少变化但被频繁调用的Prisma查询,但测试时发现,哪怕响应看起来像是来自缓存,实际还是会执行函数调用。

我的测试逻辑是:生成0-2的随机数作为缓存键,对带有4秒延迟的0-510随机数生成函数的结果做缓存。当相同的0-2数字再次出现时,我预期直接返回缓存结果,但实际还是要等函数执行完。

测试代码如下:

import { unstable_cache } from "next/cache";
export const dynamic = "force-dynamic";
import { Suspense } from "react";

export default async function Out() {
  return (
    <div>
      <h2>Test Unstable Cache</h2>
      <Suspense fallback="Grabbing random number">
        <Test />
      </Suspense>
    </div>
  );
}
async function Test() {
  const numberUsed = await getRandomInt(2);
  const cacheValue = `numberUsed_${numberUsed}`;

  console.log(cacheValue);
  // Use async/await to fetch and cache data
  const cacheResponse = await unstable_cache(
    async () => getRandomInt(510), 
    [cacheValue],
    { revalidate: 90000 },
  )();

  console.log(numberUsed + " returns " + cacheResponse);
  let text = numberUsed + " returns " + cacheResponse;

  return text;
}

async function getRandomInt(max) {
  console.log("miss");
  const delay = (ms) => new Promise((res) => setTimeout(res, ms));

  await delay(4000);
  return Math.floor(Math.random() * max);
}
问题原因与解决办法

核心问题:force-dynamic 禁用了缓存

你在页面组件顶部声明的export const dynamic = "force-dynamic";会强制页面每次请求都重新渲染,完全绕过Next.js的所有缓存机制,包括unstable_cache。这就是为什么每次都会触发getRandomInt执行的根本原因。

解决步骤

  1. 调整dynamic配置

    • 如果页面不需要完全动态,直接删除export const dynamic = "force-dynamic";,默认的auto模式会自动启用缓存。
    • 若页面确实需要部分动态内容,可改用dynamic = "auto"(默认)或dynamic = "force-static"(适合静态为主、少量动态的场景)。
  2. 优化unstable_cache的使用方式

    • 建议将缓存函数的定义移出组件渲染逻辑,避免每次组件渲染都重新创建缓存实例,示例代码如下:
import { unstable_cache } from "next/cache";
import { Suspense } from "react";

// 缓存函数定义在组件外部,确保全局唯一
const cachedRandomInt = unstable_cache(
  async (max) => getRandomInt(max),
  [],
  { revalidate: 90000 }
);

export default async function Out() {
  return (
    <div>
      <h2>Test Unstable Cache</h2>
      <Suspense fallback="Grabbing random number">
        <Test />
      </Suspense>
    </div>
  );
}

async function Test() {
  const numberUsed = await getRandomInt(2);
  // 调用时传入动态缓存键
  const cacheResponse = await cachedRandomInt(510, [`numberUsed_${numberUsed}`]);

  console.log(`${numberUsed} returns ${cacheResponse}`);
  return `${numberUsed} returns ${cacheResponse}`;
}

async function getRandomInt(max) {
  console.log("miss");
  const delay = (ms) => new Promise((res) => setTimeout(res, ms));
  await delay(4000);
  return Math.floor(Math.random() * max);
}

额外注意事项

  • unstable_cache属于实验性API,未来可能存在变更,生产环境使用需谨慎评估。
  • 用于缓存的Prisma查询需保证是纯函数(相同输入返回相同结果),否则缓存会失效。

内容的提问来源于stack exchange,提问作者Radium Chris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 22:43:29