You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5.2 KiB
5.2 KiB
ADR 002: 分镜看板性能优化架构
状态
提议中 (Proposed)
背景
当前分镜看板 API 一次性返回所有分镜数据,当项目包含 200+ 分镜时,会导致:
- 首次加载慢(2-5秒)
- 数据传输量大(300-500 KB)
- 内存占用高
- 滚动性能差
决策
采用三层数据架构 + 虚拟滚动的方案,实现高性能的分镜看板。
1. 数据分层策略
Layer 1: 骨架数据(Skeleton API)
用途:初始加载,获取所有分镜的基础信息
接口:
GET /api/v1/projects/{project_id}/storyboard-board/skeleton
响应:
{
"projectId": "xxx",
"totalDuration": 600,
"storyboardCount": 200,
"tracks": [
{
"type": "storyboard",
"items": [
{
"id": "xxx",
"startTime": 0,
"endTime": 3,
"title": "分镜 1"
}
]
}
]
}
数据量:200 分镜 ≈ 10-20 KB
Layer 2: 时间范围详细数据(Time Range API)
用途:加载可视区域的详细数据
接口(已存在):
GET /api/v1/projects/{project_id}/storyboard-board/items/time-range
?startTime=0
&endTime=60
&trackTypes=storyboard,resource,video
响应:
{
"items": [
{
"id": "xxx",
"type": "storyboard",
"startTime": 0,
"endTime": 3,
"data": {
"id": "xxx",
"title": "分镜 1",
"description": "...",
"thumbnail_url": "...",
"resources": {...}
}
}
]
}
数据量:可视区域 20 分镜 ≈ 10-15 KB
Layer 3: 单个分镜详细数据(已存在)
用途:点击分镜时加载完整信息
接口:
GET /api/v1/storyboards/{storyboard_id}
2. 前端架构
数据管理
// 使用 TanStack Query 管理三层数据
const { data: skeleton } = useStoryboardBoardSkeleton(projectId);
const { data: visibleItems } = useStoryboardBoardTimeRange(projectId, timeRange);
const { data: storyboard } = useStoryboard(selectedStoryboardId);
虚拟滚动
// 使用 react-window 实现虚拟滚动
import { VariableSizeList } from 'react-window';
<VariableSizeList
height={600}
itemCount={skeleton.items.length}
itemSize={getItemSize}
width="100%"
>
{Row}
</VariableSizeList>
时间范围计算
// 根据滚动位置计算可视时间范围
const calculateVisibleTimeRange = (scrollLeft: number, containerWidth: number, pps: number) => {
const startTime = scrollLeft / pps;
const endTime = (scrollLeft + containerWidth) / pps;
const buffer = 30; // 预加载 30 秒
return {
startTime: Math.max(0, startTime - buffer),
endTime: endTime + buffer
};
};
3. 加载策略
初始加载
- 加载骨架数据(所有分镜基础信息)
- 计算总时长和布局
- 加载初始可视区域的详细数据
滚动加载
- 监听滚动事件(防抖 200ms)
- 计算新的可视时间范围
- 加载新区域的详细数据
- 缓存已加载的数据
预加载策略
- 预加载相邻 30 秒的数据
- 滚动方向预测(向右滚动时优先加载右侧)
- 缩放时重新计算可视范围
4. 缓存策略
// TanStack Query 缓存配置
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 5 * 60 * 1000, // 5 分钟
cacheTime: 10 * 60 * 1000, // 10 分钟
},
},
});
实施计划
阶段 1:后端 API(1-2 天)
- 新增骨架数据接口
/storyboard-board/skeleton - 优化时间范围接口(已存在,需测试)
- 添加响应压缩(gzip)
阶段 2:前端基础架构(3-4 天)
- 实现骨架数据加载
- 实现时间范围加载
- 实现数据缓存管理
阶段 3:虚拟滚动(3-5 天)
- 集成 react-window
- 实现虚拟滚动渲染
- 优化滚动性能
阶段 4:优化和测试(2-3 天)
- 性能测试(1000+ 分镜)
- 内存泄漏检测
- 用户体验优化
总计:9-14 天
性能目标
| 指标 | 当前 | 目标 |
|---|---|---|
| 首次加载时间 | 2-5s | <500ms |
| 数据传输量 | 300-500 KB | <30 KB |
| 内存占用 | 随分镜数增长 | 恒定 ~50 MB |
| 滚动 FPS | 30-40 | 60 |
| 支持分镜数 | <200 | 1000+ |
优势
- 性能优异:首次加载快,滚动流畅
- 可扩展:支持大规模数据(1000+ 分镜)
- 用户体验好:无感知加载
- 架构清晰:数据分层明确,易于维护
- 向后兼容:保留现有 API,渐进式升级
劣势
- 实施复杂度高:需要前后端配合
- 开发周期长:预计 2-3 周
- 测试成本高:需要大量数据测试
替代方案
方案 A:仅移除 description 字段
- 优点:实施快(5 分钟)
- 缺点:数据量仅减少 40-60%,无法支持大规模数据
方案 B:分页加载
- 优点:实施简单
- 缺点:不适合时间轴场景,用户体验差