低端设备上让 AI 原生应用"感觉快"的实战指南
低端设备上让 AI 原生应用”感觉快”的实战指南
一句话结论:在 150 美元、3GB 内存、弱信号的手机上,让应用”感觉快”靠的不是某个单一优化——而是把首次绘制拆成流水线、让虚拟列表根据设备内存动态适配、以及把图片加载做成优先级调度系统。这三件事做到位,白屏、卡顿、图片乱跳全消失。
场景还原
做一个新闻资讯应用。首页是卡片滚动列表——标题、摘要、缩略图、日期。纸面上看着简单。
扔到一台 150 美元的 Android 手机上试试:3GB 内存,不稳定的 3G。白屏数秒。图片延迟加载挤得文字到处乱跳。滚动卡成幻灯片。应用”坏了”。
这不是假设——这是每个面向真实用户的工程师最终都要面对的场景。
第一条:首次绘制是流水线,不是单步事件
最大的思维误区:认为”首页加载=请求数据→渲染→完事”。
在低端设备上,这个模式必然导致痛苦的白屏。实际上,首次绘制应该是一串渐进的里程碑:
1 | 骨架屏 → 缓存读取 → 缓存渲染 → 网络合并 → 缓存写入 |
阶段一:骨架屏,0ms 出现
应用壳就绪的那一刻,网络字节还没到。骨架屏立刻上屏。
这不是装饰——这是心理锚点。用户看到骨架,认知从”应用坏了”切换到”应用正在加载”。
阶段二:并行拉缓存
跟网络请求同时进行,从 IndexedDB 拉缓存数据。
别用 localStorage。它是同步的,会阻塞主线程,上限约 5MB。IndexedDB 是异步的、容量可观、跨会话持久化——正好存用户上次会话最近 100 条新闻。
阶段三:缓存上屏
缓存数据一般在几十毫秒内就位。立刻用真实内容替换骨架占位符。
用户看到的是昨天的新闻,但看起来像个真正的应用——而且他们看到了东西。
阶段四:网络合并,无感更新
网络请求完成后,新数据到达。用 Map<id, item> 按新闻 ID 去重,新条目插入列表顶部。
关键:不要自动滚动。 用户可能正在浏览。改成显示一个微妙的”有新内容”提示条,用户想点再点。
阶段五:缓存回写
合并后的数据集写回 IndexedDB,LRU 淘汰策略,上限 100 条。
第二条:虚拟列表不是可选项,而且缓冲区得动态算
100 多条内容的 feed,在低端硬件上渲染每个 DOM 节点完全不可行。
虚拟列表(react-window、vue-virtual-scroller,或手写 IntersectionObserver 实现)只在 DOM 里保留可见行加一小段缓冲区。
大多数教程跳过的关键点:缓冲区大小应该是动态的,不是固定的。
- 2GB 内存设备:激进缩小预渲染窗口
- 8GB 旗舰机:放宽缓冲区,追求丝滑
用 navigator.deviceMemory 或基于初始渲染时间的粗略启发式来决定。在 2GB 设备上套用旗舰机的固定缓冲区,结果就是 OOM 崩溃。
第三条:图片加载的正确姿势——优先级调度
标准建议是”用 IntersectionObserver 懒加载”。问题是:弱连接下,图片请求一旦发起就占住网络槽位直到完成——即使用户已经滚过去了。
结果:三个并发图片下载抢 200KB/s 的带宽。用户正在看的那张最后才加载完。应用感觉慢,不是因为它慢,而是加载顺序错了。
生产级图片加载器做对三件事:
停留时间阈值
卡片进入视口那一瞬间不请求图片。等它稳定可见约 300ms 再请求。
快速滚动中卡片一闪而过——不值得加载。这直接避免了浪费的带宽消耗。
离屏取消
如果卡片在图片加载完成之前滚出视口,用 AbortController 中止 fetch。
在受限网络上,把释放的带宽给当前视口的图片——感知性能提升巨大。
优先级队列
三级调度:
- 可见区图片:立即派发
- 预渲染缓冲区:低优先级
- 已滚出屏幕:直接取消
第四条:弱网络和离线不是”加分项”
三个互补策略,缺一不可:
navigator.connection.effectiveType报告slow-2g或2g时,自动降级图片质量——请求缩略图而非全分辨率- 对图片 fetch 设激进超时,别让卡死的下载永久阻塞队列
- 网络完全离线时,从 IndexedDB 缓存渲染,图片位用灰色占位块代替
应用永远不应该因为网络不可用就显示空白屏幕。 这不是性能优化——这是基本可用性。
第五条:内存纪律
低端设备在你没注意的时候就崩了。三条规则:
- 虚拟列表缓冲区根据
navigator.deviceMemory动态适配 - 已解码图片位图在配置的 TTL 后从内存 LRU 缓存淘汰
- 快速滚动期间——通过对比
requestAnimationFrame各帧时间戳检测——完全跳过图片解码,显示缓存缩略图或占位符。滚动速度降到阈值以下再恢复解码
一句话总结
这些不是学术优化。它们区分了”在开发者的 MacBook Pro 上跑的应用”和”在偏远村庄一格信号的手机上跑的应用”。
在 AI 原生应用里,模型推理已经额外增加了延迟。把前端这些细节丢下不管,等于把你最承受不起的性能损失白白扔在桌上。