我的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
相关产品推荐
相关产品推荐

