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

Next.js全局API复用致页面卡顿,求正确实现方案

问题分析与解决方案

问题背景

在Next.js博客应用中,多个页面(文章、分类、标签、作者等)需要重复调用两个相同的外部API获取内容。为避免重复代码,我尝试创建全局API调用,代码如下:

import { getAuthors } from "@/libs/getAuthors";
import { getPosts } from "@/libs/getPosts"; 

export async function getStaticProps() {
  return {
    props: {
      posts: getPosts(),
      authors: getAuthors(),
    },
    revalidate: 1,
  };
}

同时在next.config.js中添加了以下配置:

module.exports = {
  images: {
    domains: ["images.ctfassets.net"],
  },
  webpack: (config) => {
    config.experiments = { topLevelAwait: true, layers: true };
    return config;
  },
};

虽然方案能运行,但页面加载速度大幅变慢。请问原因是什么?创建并使用此类全局API调用的正确方式是什么?

补充的getAuthors代码:

import { createClient } from "contentful";

const client = createClient({
  space: process.env.CONTENTFUL_SPACE_ID,
  accessToken: process.env.CONTENTFUL_ACCESS_KEY,
});

const auth_data = await client.getEntries({ content_type: "author" });

export function getAuthors() {
  var authors = [];

  var auth_len = auth_data.items.length;
  for (var i = 0; i < auth_len; i++) {
    authors.push({
      authorSlug: auth_data.items[i].fields.name
        .toString()
        .replace(/ /g, "-")
        .toLowerCase(),
      authorContent: auth_data.items[i].fields.description,
      authorFrontMatter: {
        title: auth_data.items[i].fields.name,
        image: "https:" + auth_data.items[i].fields.image.fields.file.url,
      },
    });
  }
  return authors;
}

页面加载变慢的原因

核心问题出在顶层await的错误使用:

  • 你在getAuthors.js模块的顶层直接执行await client.getEntries(...),这会导致模块加载时就触发API请求,且请求会阻塞整个模块的加载流程——所有依赖该模块的页面,都要等API请求完成后才能继续渲染,直接拖慢页面启动速度。
  • 若多个页面都导入getAuthors,会重复触发相同的API请求(模块缓存对顶层await的处理不可靠),进一步增加服务器和网络开销。
  • 另外,getStaticProps中调用getPosts()和getAuthors()时未使用await,但实际依赖的是顶层await获取的数据,无法并行处理两个API请求,进一步降低效率。

正确的全局API调用方式

要解决重复代码和性能问题,需将API请求逻辑封装为异步函数,在页面的getStaticProps/getServerSideProps中按需调用,同时利用缓存机制避免重复请求。

步骤1:重构API封装函数

把getAuthors和getPosts改成异步函数,不在模块顶层执行请求:

// @/libs/getAuthors.js
import { createClient } from "contentful";

const client = createClient({
  space: process.env.CONTENTFUL_SPACE_ID,
  accessToken: process.env.CONTENTFUL_ACCESS_KEY,
});

export async function getAuthors() {
  // 仅在函数调用时发起API请求
  const auth_data = await client.getEntries({ content_type: "author" });
  
  return auth_data.items.map(item => ({
    authorSlug: item.fields.name
      .toString()
      .replace(/ /g, "-")
      .toLowerCase(),
    authorContent: item.fields.description,
    authorFrontMatter: {
      title: item.fields.name,
      image: "https:" + item.fields.image.fields.file.url,
    },
  }));
}

同理重构getPosts函数,确保请求在函数内部异步执行。

步骤2:在页面中并行调用API

在需要数据的页面getStaticProps中,用Promise.all并行执行两个API请求,减少总耗时:

import { getAuthors } from "@/libs/getAuthors";
import { getPosts } from "@/libs/getPosts"; 

export async function getStaticProps() {
  // 并行请求,提升效率
  const [posts, authors] = await Promise.all([
    getPosts(),
    getAuthors()
  ]);

  return {
    props: { posts, authors },
    revalidate: 1, // ISR缓存,1秒后重新验证内容
  };
}

步骤3:移除不必要的Webpack配置

因为不再使用顶层await,可删除next.config.js中的topLevelAwait配置:

module.exports = {
  images: {
    domains: ["images.ctfassets.net"],
  },
  // 移除以下配置
  // webpack: (config) => {
  //   config.experiments = { topLevelAwait: true, layers: true };
  //   return config;
  // },
};

可选:添加请求缓存

若希望在多个页面间共享API请求结果,可实现简单的内存缓存:

// @/libs/getAuthors.js
import { createClient } from "contentful";

const client = createClient({
  space: process.env.CONTENTFUL_SPACE_ID,
  accessToken: process.env.CONTENTFUL_ACCESS_KEY,
});

// 内存缓存,避免重复请求
let cachedAuthors = null;
const CACHE_EXPIRE = 5 * 60 * 1000; // 5分钟过期

export async function getAuthors() {
  if (cachedAuthors) {
    return cachedAuthors;
  }
  
  const auth_data = await client.getEntries({ content_type: "author" });
  cachedAuthors = auth_data.items.map(item => ({
    authorSlug: item.fields.name
      .toString()
      .replace(/ /g, "-")
      .toLowerCase(),
    authorContent: item.fields.description,
    authorFrontMatter: {
      title: item.fields.name,
      image: "https:" + item.fields.image.fields.file.url,
    },
  }));
  
  // 设置缓存过期
  setTimeout(() => { cachedAuthors = null; }, CACHE_EXPIRE);
  return cachedAuthors;
}

这样多个页面调用getAuthors时,只会发起一次API请求,后续直接返回缓存数据,进一步提升性能。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 05:15:43