TTQ 相册自动播放与懒加载排障
记录 TTQ 相册从资源加载、音乐自动播放到进度条跳转的一次完整排障和验证过程。
背景与目标
这次对话的核心目标,是把 TTQ 相册从一个能打开但体验不稳定的静态站点,调整成加载更快、音乐自动播放可靠、进度条可跳转、控制状态一致的相册应用。
前置环境里还处理了 SSH 空闲断连和 Docker 域名映射。SSH 问题通过客户端与服务端 keepalive 降低空闲连接被中间网络设备断开的概率;域名排查则确认 ttq 和 wedding 两个 nginx 容器都挂载同一个 /home/pichu/dist 静态目录,所以二者除了访问域名和容器入口不同,实际服务的是同一份相册文件。
主要步骤
步骤一:定位相册部署目录
排查从 Docker 容器和 nginx 挂载关系开始。wedding 和 ttq 两个容器都使用 nginx:alpine,并把宿主机目录挂到容器内的 /usr/share/nginx/html。最终确认相册的代码和静态资源都在:
1
/home/pichu/dist
这一步很关键,因为后续所有修复都直接作用于构建产物:index.html、assets/*.js 和 assets/*.css。
步骤二:把全量加载改成渐进加载
原始问题是相册一进入页面就尝试加载大量图片和音乐资源。网络慢时,浏览器忙于下载后面的图片,反而影响了最早需要展示的照片和第一首背景音乐,导致轮播开始了但音乐没有及时响起。
修复思路是区分优先级:
- 第一首歌和当前页附近的几张照片优先加载;
- 当前照片附近保留一个小窗口,满足轮播和手动切换;
- 后续图片改成后台逐步预加载;
- 页面不再因为 400 多张照片一起请求而拖慢首屏体验。
这不是简单地少加载资源,而是把资源加载顺序改成符合用户感知的顺序:先保证马上能看到、能听到,再慢慢补齐后面的内容。
步骤三:修正自动播放的音源控制
音乐问题经历了几轮排查。最初的表现是进入页面后不自动播放,必须先点暂停再点播放才有声音。后来为了绕过浏览器自动播放限制,利用密码提交这个用户手势触发播放,解决了自动播放启动问题。
但新的 bug 随之出现:页面里同时存在两个音源。一个是在密码提交后启动的全局音频对象,另一个是页面播放按钮重新创建或控制的音频对象。结果是用户点播放后会出现两路声音,点暂停只能停掉后启动的那一路,最早自动播放的声音不受控制。
最终修复方向是统一音源:
- 页面只保留一个全局可控的
Audio实例; - 播放按钮、暂停按钮、自动播放逻辑都操作同一个对象;
- 建立音频注册和复用机制,避免重复创建第二个播放通道;
- 移除或绕开会制造重复音源的 DOM
<audio>控件。
修复后,自动播放和手动控制才真正进入同一个状态机:自动响起的是这个音源,按钮控制的也是这个音源。
步骤四:暂停后继续播放不再重头开始
音源统一后又暴露出一个细节:暂停后再播放会从头开始,而不是从刚才停下的位置继续。这种体验违背了用户对音乐播放器的基本预期。
问题本质是暂停逻辑或重新播放逻辑重置了 currentTime。修复后,暂停只调用暂停行为,不清空播放进度;再次播放时复用当前音频对象和当前位置。只有切歌或明确需要重置时,才应该把时间归零。
步骤五:让进度条按全量照片跳转
图片懒加载之后,时间轴进度条也一度跟着变成了懒加载窗口的进度。比如总共有 427 张照片,当前只加载前几张时,进度条只能在前几张之间移动,用户无法直接拖到中间或结尾。
这暴露出两个概念需要分离:
| 概念 | 含义 |
|---|---|
| 渲染窗口 | 当前真正加载和渲染的少量图片 |
| 全量序列 | 相册完整的 427 张照片顺序 |
进度条应该基于全量序列计算位置,而不是基于已加载窗口。修复后,用户点击或拖到 50% 时,会直接映射到约第 214 张照片;即使该照片尚未加载,也会立即把渲染窗口移动到对应位置,并从那里开始加载附近图片。
这样既保留了懒加载的性能收益,又保留了完整相册导航能力。
步骤六:修复白屏并做浏览器验证
调整进度条时曾出现白屏。排查后确认是压缩后的构建 JS 中多了一个 },导致脚本解析失败。修复语法错误后,没有只停留在静态检查,而是用 Playwright 起了本地测试页做浏览器验证。
验证覆盖了几件事:
- 生产域名密码页能正常显示;
- 本地绕过密码后相册能进入主界面;
- 控制台没有页面级错误;
- 进度条点击 50% 后位置和照片序号变化正确;
- 按 End 能跳到最后一张;
- 图片请求数量保持在小范围内,说明懒加载仍然有效;
ttq和wedding两个域名加载的是同一份构建资源。
核心结论
这次排障的核心不是单点修 bug,而是把 TTQ 相册里的几个状态边界重新理清。
第一,资源加载要按用户感知排序。相册首屏最重要的是第一首歌和当前几张照片,不是把完整资源列表尽快塞进网络队列。
第二,自动播放和手动控制必须共享同一个音源。只要自动播放路径和按钮路径各自创建或控制不同的 Audio 对象,就一定会出现双声道、暂停失效、状态不同步等问题。
第三,懒加载不等于业务序列变短。渲染层可以只加载附近图片,但导航层必须仍然知道完整照片列表,否则进度条、跳转、键盘导航都会退化成局部窗口导航。
第四,前端体验问题不能只靠目测确认。白屏、重复音源、懒加载窗口和进度条映射这类问题,最终都需要真实浏览器环境验证。Playwright 的价值在于它能同时检查页面是否可见、控制台是否报错、用户交互是否生效、资源请求是否符合预期。
参考
- 相册静态目录:
/home/pichu/dist - Docker 容器:
ttq、wedding - 关键资源:
index.html、assets/index-lazy-LtXTssAT.js、assets/index-XwrPCAxE.css - 验证工具:Playwright、Chromium、本地
python3 -m http.server