performance
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePerformance Skill
性能优化技能
Performance Targets
性能目标
Frontend (Web Vitals): LCP < 2.5s, FID < 100ms, CLS < 0.1, FCP < 1.8s, TTFB < 600ms
Backend: Response time < 500ms (p95), cold start < 2s, error rate < 1%
Database: Query time < 100ms, cache hit rate > 80%
前端(Web Vitals): LCP < 2.5秒,FID < 100毫秒,CLS < 0.1,FCP < 1.8秒,TTFB < 600毫秒
后端: 响应时间 < 500毫秒(p95),冷启动时间 < 2秒,错误率 < 1%
数据库: 查询时间 < 100毫秒,缓存命中率 > 80%
Measure Performance
性能测量
bash
undefinedbash
undefinedLighthouse audit
Lighthouse 审计
npx lighthouse https://sgcarstrends.com --view
npx lighthouse https://sgcarstrends.com --view
Bundle analysis
包体积分析
cd apps/web && ANALYZE=true pnpm build
cd apps/web && ANALYZE=true pnpm build
Load test with k6
使用k6进行负载测试
k6 run --vus 100 --duration 5m load-test.js
undefinedk6 run --vus 100 --duration 5m load-test.js
undefinedBundle Size Optimization
包体积优化
Dynamic Imports
动态导入
typescript
// ❌ Static import (loads immediately)
import { HeavyComponent } from "./heavy-component";
// ✅ Dynamic import (lazy load)
import dynamic from "next/dynamic";
const HeavyComponent = dynamic(() => import("./heavy-component"), {
loading: () => <div>Loading...</div>,
ssr: false,
});typescript
// ❌ 静态导入(立即加载)
import { HeavyComponent } from "./heavy-component";
// ✅ 动态导入(懒加载)
import dynamic from "next/dynamic";
const HeavyComponent = dynamic(() => import("./heavy-component"), {
loading: () => <div>加载中...</div>,
ssr: false,
});Tree Shaking
Tree Shaking
typescript
// ❌ Imports entire library
import _ from "lodash";
// ✅ Import only what you need
import uniq from "lodash/uniq";typescript
// ❌ 导入整个库
import _ from "lodash";
// ✅ 仅导入所需部分
import uniq from "lodash/uniq";React Performance
React性能优化
Prevent Re-renders
避免不必要重渲染
typescript
// useMemo for expensive calculations
const processed = useMemo(() => expensiveOperation(data), [data]);
// useCallback for stable function references
const handleClick = useCallback(() => doSomething(), []);
// React.memo for pure components
const Child = React.memo(function Child({ name }) {
return <div>{name}</div>;
});typescript
// useMemo用于昂贵计算
const processed = useMemo(() => expensiveOperation(data), [data]);
// useCallback用于稳定函数引用
const handleClick = useCallback(() => doSomething(), []);
// React.memo用于纯组件
const Child = React.memo(function Child({ name }) {
return <div>{name}</div>;
});Virtualize Long Lists
长列表虚拟化
typescript
import { FixedSizeList } from "react-window";
<FixedSizeList height={600} itemCount={items.length} itemSize={100} width="100%">
{({ index, style }) => <Item style={style} data={items[index]} />}
</FixedSizeList>typescript
import { FixedSizeList } from "react-window";
<FixedSizeList height={600} itemCount={items.length} itemSize={100} width="100%">
{({ index, style }) => <Item style={style} data={items[index]} />}
</FixedSizeList>Database Query Optimization
数据库查询优化
Add Indexes
添加索引
typescript
// packages/database/src/schema/cars.ts
export const cars = pgTable("cars", {
make: text("make").notNull(),
month: text("month").notNull(),
}, (table) => ({
makeIdx: index("cars_make_idx").on(table.make),
}));typescript
// packages/database/src/schema/cars.ts
export const cars = pgTable("cars", {
make: text("make").notNull(),
month: text("month").notNull(),
}, (table) => ({
makeIdx: index("cars_make_idx").on(table.make),
}));Avoid N+1 Queries
避免N+1查询
typescript
// ❌ N+1 queries
for (const post of posts) {
post.author = await db.query.users.findFirst({ where: eq(users.id, post.authorId) });
}
// ✅ Single query with relation
const posts = await db.query.posts.findMany({ with: { author: true } });typescript
// ❌ N+1查询
for (const post of posts) {
post.author = await db.query.users.findFirst({ where: eq(users.id, post.authorId) });
}
// ✅ 关联查询一次获取
const posts = await db.query.posts.findMany({ with: { author: true } });Select Only Needed Columns
仅选择所需列
typescript
// ❌ Selects all columns
const users = await db.query.users.findMany();
// ✅ Select specific columns
const users = await db.select({ id: users.id, name: users.name }).from(users);typescript
// ❌ 查询所有列
const users = await db.query.users.findMany();
// ✅ 仅查询指定列
const users = await db.select({ id: users.id, name: users.name }).from(users);Use Pagination
使用分页
typescript
const cars = await db.query.cars.findMany({
limit: 20,
offset: (page - 1) * 20,
});typescript
const cars = await db.query.cars.findMany({
limit: 20,
offset: (page - 1) * 20,
});Caching
缓存策略
Redis Caching
Redis缓存
typescript
import { redis } from "@sgcarstrends/utils";
export async function getCarsWithCache(make: string) {
const cacheKey = `cars:${make}`;
const cached = await redis.get(cacheKey);
if (cached) return JSON.parse(cached as string);
const cars = await db.query.cars.findMany({ where: eq(cars.make, make) });
await redis.set(cacheKey, JSON.stringify(cars), { ex: 3600 });
return cars;
}typescript
import { redis } from "@sgcarstrends/utils";
export async function getCarsWithCache(make: string) {
const cacheKey = `cars:${make}`;
const cached = await redis.get(cacheKey);
if (cached) return JSON.parse(cached as string);
const cars = await db.query.cars.findMany({ where: eq(cars.make, make) });
await redis.set(cacheKey, JSON.stringify(cars), { ex: 3600 });
return cars;
}Next.js Caching
Next.js缓存
typescript
// Revalidate every hour
export const revalidate = 3600;
// Or use fetch with caching
const data = await fetch(url, { next: { revalidate: 3600 } });typescript
// 每小时重新验证一次
export const revalidate = 3600;
// 或使用fetch配置缓存
const data = await fetch(url, { next: { revalidate: 3600 } });Image Optimization
图片优化
typescript
import Image from "next/image";
// ✅ Optimized image with priority for above-fold
<Image
src="/hero.jpg"
alt="Hero"
fill
sizes="(max-width: 768px) 100vw, 50vw"
priority
/>typescript
import Image from "next/image";
// ✅ 优化首屏图片并设置优先级
<Image
src="/hero.jpg"
alt="Hero"
fill
sizes="(max-width: 768px) 100vw, 50vw"
priority
/>Vercel Function Optimization
Vercel函数优化
typescript
// API route with optimized config
export const config = {
maxDuration: 60, // seconds
};
// Use edge functions for low-latency endpoints
export const runtime = "edge";typescript
// API路由优化配置
export const config = {
maxDuration: 60, // 秒
};
// 为低延迟端点使用Edge函数
export const runtime = "edge";Profiling
性能分析
Performance Middleware
性能中间件
typescript
// apps/api/src/middleware/performance.ts
export const performanceMiddleware = async (c: Context, next: Next) => {
const start = performance.now();
await next();
const duration = performance.now() - start;
c.header("X-Response-Time", `${Math.round(duration)}ms`);
if (duration > 1000) {
log.warn("Slow request", { path: c.req.path, duration: Math.round(duration) });
}
};typescript
// apps/api/src/middleware/performance.ts
export const performanceMiddleware = async (c: Context, next: Next) => {
const start = performance.now();
await next();
const duration = performance.now() - start;
c.header("X-Response-Time", `${Math.round(duration)}ms`);
if (duration > 1000) {
log.warn("Slow request", { path: c.req.path, duration: Math.round(duration) });
}
};Query Profiling
查询性能分析
typescript
const start = performance.now();
const result = await db.query.cars.findMany();
const duration = performance.now() - start;
if (duration > 100) {
console.warn(`Slow query: ${duration}ms`);
}typescript
const start = performance.now();
const result = await db.query.cars.findMany();
const duration = performance.now() - start;
if (duration > 100) {
console.warn(`Slow query: ${duration}ms`);
}Vercel Analytics
Vercel分析工具
Check Vercel Dashboard → Analytics for:
- Function execution times
- Edge response times
- Web Vitals metrics
- Request volumes and errors
查看Vercel控制台 → 分析页面获取以下数据:
- 函数执行时间
- Edge响应时间
- Web Vitals指标
- 请求量与错误率
Load Testing
负载测试
javascript
// load-test.js (k6)
import http from "k6/http";
import { check } from "k6";
export const options = {
stages: [
{ duration: "2m", target: 100 },
{ duration: "5m", target: 100 },
{ duration: "2m", target: 0 },
],
thresholds: {
http_req_duration: ["p(95)<500"],
http_req_failed: ["rate<0.01"],
},
};
export default function() {
const res = http.get("https://api.sgcarstrends.com/api/v1/cars/makes");
check(res, { "status 200": (r) => r.status === 200 });
}javascript
// load-test.js (k6)
import http from "k6/http";
import { check } from "k6";
export const options = {
stages: [
{ duration: "2m", target: 100 },
{ duration: "5m", target: 100 },
{ duration: "2m", target: 0 },
],
thresholds: {
http_req_duration: ["p(95)<500"],
http_req_failed: ["rate<0.01"],
},
};
export default function() {
const res = http.get("https://api.sgcarstrends.com/api/v1/cars/makes");
check(res, { "status 200": (r) => r.status === 200 });
}Performance Checklist
性能检查清单
- Bundle size < 200KB (initial load)
- LCP < 2.5s, FID < 100ms, CLS < 0.1
- API responses < 500ms
- Database queries < 100ms
- Images optimized (WebP/AVIF)
- Code splitting implemented
- Caching strategy in place
- Long lists virtualized
- Compression enabled
- 初始加载包体积 < 200KB
- LCP < 2.5秒,FID < 100毫秒,CLS < 0.1
- API响应时间 < 500毫秒
- 数据库查询时间 < 100毫秒
- 图片已优化(WebP/AVIF格式)
- 已实现代码分割
- 已制定缓存策略
- 长列表已虚拟化
- 已启用压缩
Quick Wins
快速优化方案
- Compression: Enable gzip/brotli (60-80% size reduction)
- Image Optimization: Use Next.js Image component
- Caching: Cache expensive operations in Redis
- Indexes: Add indexes to frequently queried columns
- Code Splitting: Lazy load heavy components
- Memoization: Use useMemo/useCallback for expensive operations
- 压缩配置:启用gzip/brotli压缩(可减少60-80%的体积)
- 图片优化:使用Next.js Image组件
- 缓存实现:将昂贵操作缓存至Redis
- 索引添加:为高频查询列添加索引
- 代码分割:懒加载大型组件
- 记忆化处理:对昂贵操作使用useMemo/useCallback
References
参考资料
- Web Vitals: https://web.dev/vitals
- Next.js Performance: https://nextjs.org/docs/app/building-your-application/optimizing
- k6 Load Testing: https://k6.io/docs
- Web Vitals: https://web.dev/vitals
- Next.js性能优化: https://nextjs.org/docs/app/building-your-application/optimizing
- k6负载测试: https://k6.io/docs