这类问题看似集中在一个 API 或参数上,真正决定可用性的却是状态归属、资源上限和失败后的恢复方式。 虚拟列表减少 DOM 数量,却会复用节点和卸载屏外内容。若 key 用数组索引、行高测量不稳定或新事件插到顶部,用户看到的滚动位置和焦点都会跳。
前端架构的核心不是目录层级,而是状态由谁拥有、事件能否重复执行、旧异步结果如何失效,以及卸载后监听器和资源是否真正归零。
先把实现决策说清楚
先把下面几项写成可评审的规则,而不是散落在回调和界面判断里。规则越清楚,后续扩容、兼容和排错越少靠猜。
- 实体 ID 作为 key,渲染窗口与数据排序分开,禁止用可变索引标识。
- 顶部插入时记录可见锚点与偏移,更新后恢复而不是硬改 scrollTop。
- 为屏幕阅读器提供总数、位置语义与非虚拟分页模式或可达搜索。
虚拟化的成功标准不是滚动帧率一个数字,而是大数据量下位置、焦点和实体身份仍稳定,用户始终找得到刚才那一条。
最容易漏掉的失败路径
生产问题往往发生在两个正确动作同时到达时。需要逐条检查迟到消息、重复执行、资源耗尽和版本交叉,而不是只补当前堆栈显示的那一行。
- 筛选后复用旧高度缓存,行内容变化造成累计滚动误差。
- 焦点行滚出窗口被卸载,键盘下一步回到页面顶部。
- 每条实时事件都重算全部列表,虚拟化仍被排序与响应式开销拖慢。
上线前怎样验证
发布闸门应包含确定性回归、随机时序探索和真实浏览器组合。发现一次失败后保存 seed 与状态轨迹,让它永久成为可重放用例。
- 连续追加、头部插入、删除和筛选时保持同一锚点与焦点实体。
- 用不同字体缩放与中英文长标题验证动态行高缓存可纠正。
- 测量 DOM 数、长任务和内存,并用键盘与屏幕阅读器完成记录查找。
当实现能够安全降级、重复执行不产生额外副作用、故障指标早于投诉出现时,这项能力才算具备长期维护价值。