mobile wallpaper 1
mobile wallpaper 2
mobile wallpaper 3
mobile wallpaper 4
2434 字
6 分钟
博客为什么这么慢:视频、音乐、看板娘和一个连不上的图标服务器
2026-11-03

背景视频 6.4 MB → 1.6 MB · 看板娘贴图 1.1 MB → 0.24 MB · 控制台里的红字少了一大片
但有一件事,压缩解决不了。

起点:搬上服务器,然后发现它很慢#

上一篇把博客搬上了服务器,24 小时在线了。

然后打开首页:背景视频半天不动,音乐点了没声音,右下角的看板娘干脆没出来。打开控制台,一片红。

这一篇记录这晚的排查。

第零个坑:明明发了文章,首页却没有#

上一篇发出去之后,我自己的浏览器里首页还是旧的:归档 5 篇、项目 3 篇,新文章不见了。

先一层层排除:

检查结果
服务器上的文件新版
Cloudflare 缓存没缓存,每次回源
直接请求首页新版
代理 / Service Worker都没有

只剩浏览器自己。服务器之前没告诉浏览器「网页要每次重新确认」,浏览器就心安理得地用着旧页面。

修法是给 HTML 加一行响应头:

location ~* \.html?$ { add_header Cache-Control "no-cache" always; }

no-cache 不是「不缓存」,而是「用之前先问一句有没有更新」。图片、样式照常长期缓存,只有网页本身每次确认。

第一步:先量,再改#

把首页上几个大文件挨个测了一遍下载时间:

文件大小下载时间
背景视频6.4 MB60 秒还没下完
歌曲2.7 MB34 秒
看板娘贴图1.1 MB9–16 秒
看板娘渲染脚本644 KB5 秒

速度只有每秒几十到一百多 KB。文件又大,叠在一起就是「半天不动」。

第二步:能压的都压一遍#

背景视频:6.4 MB → 1.6 MB#

这段视频有几个特点:

  • 画面上本来就加了 6px 模糊,再清晰也看不出来
  • 它是静音播放的,但文件里带着一条音轨
  • 640×360、30 帧

所以:去掉音轨,降到 480 宽、24 帧,提高压缩率。

ffmpeg -i bg.mp4 -an -vf "scale=480:-2,fps=24" \
-c:v libx264 -preset slow -crf 33 -movflags +faststart bg-new.mp4

另外两处小改动:

  • 加了一张 10 KB 的封面图,视频没加载出来之前先显示第一帧,不会黑屏
  • preload="auto" 改成 preload="metadata",打开页面时不再急着把整个视频拉下来

音乐:128k → 96k#

两首歌分别从 2.7 MB、2.2 MB 降到 2.0 MB、1.7 MB。背景音乐,96k 够用。

顺手发现目录里还躺着两个 .mp3.orig,是之前压缩前的原文件,一共 12 MB,没有任何地方引用,却每次都跟着博客一起发布。移走。

看板娘贴图:4096 → 2048#

贴图是 4096×4096 的 PNG。而看板娘在页面上只有 280 像素宽。

缩到 2048×2048,1.1 MB → 0.24 MB。

还试了更狠的 pngquant 有损压缩,能压到 72 KB,但逐像素比对后,部分边缘像素的差异到了最大值 255 —— 也就是有像素颜色完全变了。贴图上一个像素对应模型的一小块,这种失真可能会在某个动作里露出来,不冒这个险,用了无损的 2048 版本。

压完之后#

文件之前之后
背景视频60 秒还没下完13–24 秒
歌曲34 秒6–9 秒
看板娘贴图9–16 秒3–5 秒

快了不少。但还是不快。

第三步:压缩解决不了的那件事#

注意看这一行:

看板娘渲染脚本,644 KB,已经被 Cloudflare 缓存(HIT),下载用了 3.8 秒。

文件已经存在 Cloudflare 的节点上,根本不用回我的服务器了,还是要 3.8 秒。

算下来,从我这边到 Cloudflare 只有 每秒 100–150 KB。免费版 Cloudflare 在国内要绕到海外节点,这条线路本身就慢。

所以结论很明确:

  • 文件大小是我能改的,已经改了
  • 线路是我改不了的,换服务器也没用

真想快,只能走另一条路(国内 CDN),而那需要先办备案。这是以后的事了。

第四步:看板娘为什么两次都加载失败#

控制台里有两行黄字:

[pio] model not loaded in 25s, retry=false
[pio] model not loaded in 25s, retry=true

看板娘的加载页里有个「看门狗」:25 秒内没加载完,就当作失败,清掉重来一次;第二次还不行,就显示「加载失败」。

这个设计本来是为了应对显卡偶尔抽风的情况。但翻服务器日志,发现真正的原因是:

  • Live2D 要依次下载十几个文件,每个小文件在我这边都要等 5–20 秒
  • 第一次和第二次,最后那张贴图都还没开始下载,25 秒就到了

不是加载失败,是还没来得及加载就被判了失败。

改法:

改动原因
超时 25 秒 → 90 秒慢网络下给足下载时间
模型配置 JSON 缓存 1 天原来每次都要回服务器确认一遍,十几个文件就是十几次往返
视频、音乐、模型文件缓存 30 天原来是 4 小时

第一次打开可能还是要等一会儿,但之后文件都在浏览器里了。

第五步:控制台里那一片红#

剩下的报错长这样,重复了很多遍:

GET https://api.unisvg.com/material-symbols.json?icons=search
net::ERR_CONNECTION_TIMED_OUT

博客里的按钮图标 —— 主题切换、搜索、音乐播放器 —— 用的是 Iconify 图标组件。图标找不到时,它会去在线服务器下载,服务器有三个:

服务器从我这边访问
api.iconify.design(官方)0.4 秒
api.simplesvg.com(备用)0.4 秒
api.unisvg.com(备用)连不上

奇怪的是:这些图标明明早就打包进博客了。项目里有一个专门的脚本,把用到的 149 个图标都提前注册好,就是为了不联网。

比对了一遍,149 个一个不缺。那为什么还要去下载?

原因:顺序反了#

看构建出来的页面,脚本的执行顺序是:

搜索框组件 ← 用到图标,本地还没有,去联网下载
主题切换组件 ← 同上
设置面板 ← 同上
……
本地图标注册 ← 排在最后

注册图标的脚本挂在页面底部,而那些组件先跑了。等图标注册好,请求早就发出去了。

修法:让组件自己先注册#

与其和执行顺序较劲,不如让「用图标的组件」和「注册图标」变成同一件事。

写了一个很小的替身模块:

// 先注册本地图标,再导出原组件
import "./iconify-local";
import { addAPIProvider } from "@iconify/svelte/dist/functions";
// 兜底时只用官方 API,去掉连不上的备用镜像
addAPIProvider("", { resources: ["https://api.iconify.design"] });
export { default } from "@iconify/svelte/dist/Icon.svelte";

然后在构建配置里,把所有 @iconify/svelte 的引用都指向这个替身。这样不管哪个组件先加载,它拿到图标组件的那一刻,本地图标就已经注册好了。

顺便还补上了一个漏网之鱼:音乐播放器缓冲时转圈的图标 svg-spinners:90-ring-with-bg,之前没被打包进去。

最后剩下的#

控制台里还有一行:

static.cloudflareinsights.com ... ERR_TIMED_OUT

这个不是博客的代码,是 Cloudflare 自动往页面里插的访问统计脚本,国内连不上。要在 Cloudflare 后台关掉,跟博客无关。

收尾:两条黄色警告#

红字清干净以后,控制台里还剩两条黄色的警告。不影响使用,但看着碍眼。

「点击进入」和读屏软件打架#

Blocked aria-hidden on an element because its descendant retained focus.
Element with focus: <button.ml-enter>

进站页(就是那个流星 +「点击进入」的遮罩)从一开始就被标记成 aria-hidden="true" —— 意思是「读屏软件请忽略我」。可它里面偏偏有一个能获得焦点的按钮。

一边说「别看我」,一边又把焦点放在自己身上,浏览器就拦了。

改法很直接:

  • 进站页显示的时候不再隐藏,它本来就是用户要操作的东西
  • 关闭的时候先让按钮失去焦点,再标记隐藏

看板娘还没出来,就在找它的「手」#

[pio] no driver found; widgetInstance keys = ...

看板娘会跟着鼠标转头,这个功能要先在 Live2D 库里找到负责拖动的那个接口。问题是它在模型加载完之前就开始找了,当然找不到,于是报了一条警告 —— 几秒后模型加载完,它又找到了:

[pio] found onDrag at ... (depth 6)

所以这条警告其实是误报。改成只在模型已经加载完、还找不到的时候才提示。

这一晚学到的#

  • 先量,再改。 不测一遍,我会以为慢是服务器的问题
  • 能压的先压,但要知道压缩的上限在哪 —— 线路慢,文件再小也只能快一些
  • 「失败」不一定是失败。 看门狗 25 秒判死刑,判的其实是网速
  • 「已经做了」不等于「已经生效」。 图标早就打包了,但执行顺序让它形同虚设
  • 有损压缩要验证。 72 KB 很诱人,但逐像素比一下,就知道不该用
  • 警告也值得看一眼。 一条是两个设计互相矛盾,一条是时机不对的误报 —— 都不是大事,但都说明了代码在想什么

本文中的排查和修改都由 AI 执行,涉及权限的每一步都先征得了我的同意。改动前的文件都留了备份。

分享

如果这篇文章对你有帮助,欢迎分享给更多人!

博客为什么这么慢:视频、音乐、看板娘和一个连不上的图标服务器
https://star-fall.159911.xyz/posts/performance-night/
作者
星落
发布于
2026-11-03
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

目录

star-fall のcafe 加载中…