文章

TTQ 相册自动播放与懒加载排障

记录 TTQ 相册从资源加载、音乐自动播放到进度条跳转的一次完整排障和验证过程。

TTQ 相册自动播放与懒加载排障
  1. 背景与目标
  2. 主要步骤
    1. 步骤一:定位相册部署目录
    2. 步骤二:把全量加载改成渐进加载
    3. 步骤三:修正自动播放的音源控制
    4. 步骤四:暂停后继续播放不再重头开始
    5. 步骤五:让进度条按全量照片跳转
    6. 步骤六:修复白屏并做浏览器验证
  3. 核心结论
  4. 参考

背景与目标

这次对话的核心目标,是把 TTQ 相册从一个能打开但体验不稳定的静态站点,调整成加载更快、音乐自动播放可靠、进度条可跳转、控制状态一致的相册应用。

前置环境里还处理了 SSH 空闲断连和 Docker 域名映射。SSH 问题通过客户端与服务端 keepalive 降低空闲连接被中间网络设备断开的概率;域名排查则确认 ttqwedding 两个 nginx 容器都挂载同一个 /home/pichu/dist 静态目录,所以二者除了访问域名和容器入口不同,实际服务的是同一份相册文件。

主要步骤

步骤一:定位相册部署目录

排查从 Docker 容器和 nginx 挂载关系开始。weddingttq 两个容器都使用 nginx:alpine,并把宿主机目录挂到容器内的 /usr/share/nginx/html。最终确认相册的代码和静态资源都在:

1
/home/pichu/dist

这一步很关键,因为后续所有修复都直接作用于构建产物:index.htmlassets/*.jsassets/*.css

步骤二:把全量加载改成渐进加载

原始问题是相册一进入页面就尝试加载大量图片和音乐资源。网络慢时,浏览器忙于下载后面的图片,反而影响了最早需要展示的照片和第一首背景音乐,导致轮播开始了但音乐没有及时响起。

修复思路是区分优先级:

  • 第一首歌和当前页附近的几张照片优先加载;
  • 当前照片附近保留一个小窗口,满足轮播和手动切换;
  • 后续图片改成后台逐步预加载;
  • 页面不再因为 400 多张照片一起请求而拖慢首屏体验。

这不是简单地少加载资源,而是把资源加载顺序改成符合用户感知的顺序:先保证马上能看到、能听到,再慢慢补齐后面的内容。

步骤三:修正自动播放的音源控制

音乐问题经历了几轮排查。最初的表现是进入页面后不自动播放,必须先点暂停再点播放才有声音。后来为了绕过浏览器自动播放限制,利用密码提交这个用户手势触发播放,解决了自动播放启动问题。

但新的 bug 随之出现:页面里同时存在两个音源。一个是在密码提交后启动的全局音频对象,另一个是页面播放按钮重新创建或控制的音频对象。结果是用户点播放后会出现两路声音,点暂停只能停掉后启动的那一路,最早自动播放的声音不受控制。

最终修复方向是统一音源:

  • 页面只保留一个全局可控的 Audio 实例;
  • 播放按钮、暂停按钮、自动播放逻辑都操作同一个对象;
  • 建立音频注册和复用机制,避免重复创建第二个播放通道;
  • 移除或绕开会制造重复音源的 DOM <audio> 控件。

修复后,自动播放和手动控制才真正进入同一个状态机:自动响起的是这个音源,按钮控制的也是这个音源。

步骤四:暂停后继续播放不再重头开始

音源统一后又暴露出一个细节:暂停后再播放会从头开始,而不是从刚才停下的位置继续。这种体验违背了用户对音乐播放器的基本预期。

问题本质是暂停逻辑或重新播放逻辑重置了 currentTime。修复后,暂停只调用暂停行为,不清空播放进度;再次播放时复用当前音频对象和当前位置。只有切歌或明确需要重置时,才应该把时间归零。

步骤五:让进度条按全量照片跳转

图片懒加载之后,时间轴进度条也一度跟着变成了懒加载窗口的进度。比如总共有 427 张照片,当前只加载前几张时,进度条只能在前几张之间移动,用户无法直接拖到中间或结尾。

这暴露出两个概念需要分离:

概念含义
渲染窗口当前真正加载和渲染的少量图片
全量序列相册完整的 427 张照片顺序

进度条应该基于全量序列计算位置,而不是基于已加载窗口。修复后,用户点击或拖到 50% 时,会直接映射到约第 214 张照片;即使该照片尚未加载,也会立即把渲染窗口移动到对应位置,并从那里开始加载附近图片。

这样既保留了懒加载的性能收益,又保留了完整相册导航能力。

步骤六:修复白屏并做浏览器验证

调整进度条时曾出现白屏。排查后确认是压缩后的构建 JS 中多了一个 },导致脚本解析失败。修复语法错误后,没有只停留在静态检查,而是用 Playwright 起了本地测试页做浏览器验证。

验证覆盖了几件事:

  • 生产域名密码页能正常显示;
  • 本地绕过密码后相册能进入主界面;
  • 控制台没有页面级错误;
  • 进度条点击 50% 后位置和照片序号变化正确;
  • 按 End 能跳到最后一张;
  • 图片请求数量保持在小范围内,说明懒加载仍然有效;
  • ttqwedding 两个域名加载的是同一份构建资源。

核心结论

这次排障的核心不是单点修 bug,而是把 TTQ 相册里的几个状态边界重新理清。

第一,资源加载要按用户感知排序。相册首屏最重要的是第一首歌和当前几张照片,不是把完整资源列表尽快塞进网络队列。

第二,自动播放和手动控制必须共享同一个音源。只要自动播放路径和按钮路径各自创建或控制不同的 Audio 对象,就一定会出现双声道、暂停失效、状态不同步等问题。

第三,懒加载不等于业务序列变短。渲染层可以只加载附近图片,但导航层必须仍然知道完整照片列表,否则进度条、跳转、键盘导航都会退化成局部窗口导航。

第四,前端体验问题不能只靠目测确认。白屏、重复音源、懒加载窗口和进度条映射这类问题,最终都需要真实浏览器环境验证。Playwright 的价值在于它能同时检查页面是否可见、控制台是否报错、用户交互是否生效、资源请求是否符合预期。

参考

  • 相册静态目录:/home/pichu/dist
  • Docker 容器:ttqwedding
  • 关键资源:index.htmlassets/index-lazy-LtXTssAT.jsassets/index-XwrPCAxE.css
  • 验证工具:Playwright、Chromium、本地 python3 -m http.server
本文由作者按照 CC BY 4.0 进行授权