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

我的Next.js静态电商应用构建时间出现红黄耗时标记是什么原因?

问题原因分析
  • Next.js 12及以上版本新增了静态页面生成耗时的告警提示:单页静态生成耗时超过2s会标黄,超过5s会标红。旧版本没有这个提示能力,所以不是旧版本构建更快,只是旧版本没有暴露这个耗时信息,属于正常的功能迭代。
    你当前代码的核心耗时问题来自以下几点:

1. 重复建立数据库连接

你在每个页面的getStaticProps中都单独调用了dbConnect(),如果你的数据库连接工具没有做单例复用,每次调用都会新建完整的数据库连接,包含TCP握手、鉴权等步骤,单次开销通常在几百毫秒到数秒不等,页面数量越多,总耗时会线性增长。

2. 重复查询数据库

你已经在getStaticPaths中查询了全量产品的slug,但是没有复用这一次查询的结果,每个页面的getStaticProps都单独发起一次数据库查询,额外增加了大量数据库IO开销。

3. 不必要的异步等待

代码中product._id = await product._id.toString()的await是冗余的,toString是同步方法,虽然对性能影响不大,但属于无效代码。

优化方案

1. 数据库连接改为单例复用

修改你的dbConnect实现,全局缓存已建立的数据库连接,后续调用直接复用已有连接,避免重复建连开销,示例实现:

// lib/dbConnect.js
import mongoose from 'mongoose'

const MONGODB_URI = process.env.MONGODB_URI

if (!MONGODB_URI) {
  throw new Error('请定义MONGODB_URI环境变量')
}

let cached = global.mongoose

if (!cached) {
  cached = global.mongoose = { conn: null, promise: null }
}

async function dbConnect() {
  if (cached.conn) {
    return cached.conn
  }

  if (!cached.promise) {
    const opts = {
      bufferCommands: false,
    }

    cached.promise = mongoose.connect(MONGODB_URI, opts).then((mongoose) => {
      return mongoose
    })
  }
  cached.conn = await cached.promise
  return cached.conn
}

export default dbConnect

2. 预取全量数据缓存复用

在getStaticPaths中一次性查询所有产品需要的全部字段,存入全局缓存,getStaticProps直接从缓存读取数据,省去每个页面的数据库查询开销:

// 全局缓存变量
const productCache = new Map()

export async function getStaticPaths() {
    await dbConnect();
    // 一次性查询所有产品需要的全部字段
    const products = await ProductModel.find({}, { slug: 1, price: 1, features: 1, item: 1, drop: 1, skus: 1 }).lean();
    // 存入缓存
    products.forEach(product => {
        product._id = product._id.toString()
        productCache.set(product.slug, product)
    })
    const paths = products.map((_product) => {
        return {
            params: { slug: _product.slug.toString() },
        };
    });
    return { paths, fallback: true };
}

export async function getStaticProps({ params }) {
    const { slug } = params;
    // 优先从缓存取
    let product = productCache.get(slug)
    // 兜底处理(fallback触发的场景)
    if (!product) {
        await dbConnect()
        product = await ProductModel.findOne(
            { slug },
            { price: 1, features: 1, item: 1, drop: 1, skus: 1 }
        ).lean();
        if (!product) {
            return { notFound: true };
        }
        product._id = product._id.toString();
    }
    return { props: { product }, revalidate: 300 };
}

3. 可选:调整告警阈值

如果你的业务逻辑确实需要较长的生成时间,也可以在next.config.js中调整告警阈值,关闭不必要的提示:

// next.config.js
module.exports = {
  experimental: {
    staticPageGenerationTimeout: 10000, // 单位毫秒,这里设置为10s后才告警
  },
}

相关疑问说明
  • 是否必须优化:如果你的产品数量很少(<10个),对构建时间要求不高,也可以不优化,这个告警只是性能提示,不影响功能正常运行。但如果产品数量较多,或者希望线上ISR增量生成的页面响应更快,强烈建议按上述方案优化。
  • 该现象是否为Next.js的bug:不属于bug,是Next.js新增的性能提示功能,本身是正常表现。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 09:06:06