

子玥酱 (掘金 / 知乎 / CSDN / 简书 同名)
大家好,我是 子玥酱,一名长期深耕在一线的前端程序媛 👩💻。曾就职于多家知名互联网大厂,目前在某国企负责前端软件研发相关工作,主要聚焦于业务型系统的工程化建设与长期维护。
我持续输出和沉淀前端领域的实战经验,日常关注并分享的技术方向包括 前端工程化、小程序、React / RN、Flutter、跨端方案,
在复杂业务落地、组件抽象、性能优化以及多端协作方面积累了大量真实项目经验。
技术方向: 前端 / 跨端 / 小程序 / 移动端工程化 内容平台: 掘金、知乎、CSDN、简书 创作特点: 实战导向、源码拆解、少空谈多落地 **文章状态:**长期稳定更新,大量原创输出
我的内容主要围绕 前端技术实战、真实业务踩坑总结、框架与方案选型思考、行业趋势解读 展开。文章不会停留在"API 怎么用",而是更关注为什么这么设计、在什么场景下容易踩坑、真实项目中如何取舍,希望能帮你在实际工作中少走弯路。
子玥酱 · 前端成长记录官 ✨
👋 如果你正在做前端,或准备长期走前端这条路
📚 关注我,第一时间获取前端行业趋势与实践总结
🎁 可领取 11 类前端进阶学习资源 (工程化 / 框架 / 跨端 / 面试 / 架构)
💡 一起把技术学"明白",也用"到位"
持续写作,持续进阶。
愿我们都能在代码和生活里,走得更稳一点 🌱
文章目录
-
- 引言
- 第一类:生命周期撕裂场景测试
-
- 错误但常见的写法
- [正确的防御思路:状态 + 收敛](#正确的防御思路:状态 + 收敛)
- 第二类:进程被杀与"非正常恢复"
- 第三类:电量与性能降级测试
-
- 错误假设
- [正确做法:基于 deltaTime](#正确做法:基于 deltaTime)
- 第四类:系统调度与资源争抢
- 第五类:网络极端波动
- 第六类:存储与数据完整性
-
- 危险写法
- [防御:临时文件 + 原子替换](#防御:临时文件 + 原子替换)
- 第七类:长时间运行疲劳测试
- 总结
引言
如果你做 HarmonyOS 游戏做到后期,大概率会有一种熟悉又不安的感觉:
"这个游戏功能都齐了,怎么越跑越不踏实?"
测试服里一切正常,
开发机上也不崩,
帧率看着也还行。
但你心里很清楚:
只要一上线,问题一定不是现在看到的这些。
因为你已经隐约意识到一件事------
真正决定游戏能不能活下来的,从来不是正常场景。
第一类:生命周期撕裂场景测试
很多问题,并不是"生命周期没处理",而是处理方式默认它是线性的。
错误但常见的写法
ts
onForeground(): void {
this.resumeGame()
}
onBackground(): void {
this.pauseGame()
}
看起来很合理,对吧? 但问题在于:
onForeground被调用- ≠ 窗口已获得焦点
- ≠ 输入系统已恢复
- ≠ 渲染节奏稳定
正确的防御思路:状态 + 收敛
ts
enum GameRunState {
Running,
Paused
}
let targetState: GameRunState = GameRunState.Paused
let actualState: GameRunState = GameRunState.Paused
onForeground() {
targetState = GameRunState.Running
}
onBackground() {
targetState = GameRunState.Paused
}
tick() {
if (targetState !== actualState) {
this.applyState(targetState)
actualState = targetState
}
}
你不再假设:
"回调一来,世界就准备好了"
而是:
"系统慢慢来,我等它稳定后再切状态。"
第二类:进程被杀与"非正常恢复"
HarmonyOS 会在你完全没犯错的情况下杀掉你。
如果你把状态只放在内存里:
ts
let level = 12
let score = 3400
那被杀一次,玩家就直接回新手村。
必须接受的现实
Ability 重建 ≠ 崩溃 ≠ Bug
正确的最小恢复模型
ts
interface GameSnapshot {
level: number
score: number
}
saveSnapshot() {
const snapshot: GameSnapshot = {
level: this.level,
score: this.score
}
Preferences.putSync('snapshot', JSON.stringify(snapshot))
}
restoreSnapshot() {
const raw = Preferences.getSync('snapshot', '')
if (!raw) return
const snapshot = JSON.parse(raw) as GameSnapshot
this.level = snapshot.level
this.score = snapshot.score
}
并且:
- 在关键节点保存
- 不要只在 onDestroy 保存
ts
onBackground() {
this.saveSnapshot()
}
因为你永远不知道:
onDestroy 会不会来。
第三类:电量与性能降级测试
最危险的性能问题是:
"没崩,但慢了。"
错误假设
ts
requestAnimationFrame(loop)
你默认每一帧都是 16ms。
正确做法:基于 deltaTime
ts
let lastTime = Date.now()
loop() {
const now = Date.now()
const delta = now - lastTime
lastTime = now
this.update(delta)
this.render()
requestAnimationFrame(loop)
}
并在 update 里做降级判断:
ts
update(delta: number) {
if (delta > 40) {
this.disableParticles()
}
}
不是追求帧完美,而是:
系统变慢时,你也跟着"收缩"。
第四类:系统调度与资源争抢
这是最容易被误判成「偶发卡顿」的一类。
高风险写法
ts
setInterval(() => {
this.aiUpdate()
}, 16)
你在和系统抢调度权。
更安全的节奏模型
ts
let accumulator = 0
update(delta: number) {
accumulator += delta
while (accumulator >= 16) {
this.aiUpdate()
accumulator -= 16
}
}
你不再强迫系统:
"我必须 60fps"
而是:
"你给我多少时间,我干多少事。"
第五类:网络极端波动
最坑的网络问题不是断网,而是:
"看起来还连着。"
危险写法
ts
await http.post('/match')
startGame()
防御式网络状态机
ts
enum NetState {
Idle,
Requesting,
Timeout,
Success
}
let netState = NetState.Idle
startMatch() {
netState = NetState.Requesting
setTimeout(() => {
if (netState === NetState.Requesting) {
netState = NetState.Timeout
showRetry()
}
}, 3000)
http.post('/match').then(() => {
netState = NetState.Success
startGame()
})
}
你要假设:
请求一定会"卡在中间"。
第六类:存储与数据完整性
写存档时被杀,是必然会发生的事。
危险写法
ts
File.writeTextSync('save.json', JSON.stringify(data))
防御:临时文件 + 原子替换
ts
File.writeTextSync('save.tmp', JSON.stringify(data))
File.renameSync('save.tmp', 'save.json')
这样即使中途被杀:
- 要么是旧存档
- 要么是新存档
- 不会是半截尸体
第七类:长时间运行疲劳测试
最容易漏的,是"慢性死亡"。
高频资源申请但不释放
ts
loadSound() {
audioManager.createPlayer(url)
}
正确做法
ts
let bgmPlayer: AudioPlayer | null = null
loadBGM() {
if (!bgmPlayer) {
bgmPlayer = audioManager.createPlayer(url)
}
}
onBackground() {
bgmPlayer?.release()
bgmPlayer = null
}
你要假设:
用户会挂着你很久。
总结
加完这些代码你会发现一件事:
HarmonyOS 游戏的稳定性,不来自"写对了什么",
而来自"你提前假设它一定会被打断"。
这些极端测试不是用来"证明你很强",而是用来确认一件事:
当系统不再站在你这边时,你的游戏还能不能活下来。