

子玥酱 (掘金 / 知乎 / CSDN / 简书 同名)
大家好,我是 子玥酱,一名长期深耕在一线的前端程序媛 👩💻。曾就职于多家知名互联网大厂,目前在某国企负责前端软件研发相关工作,主要聚焦于业务型系统的工程化建设与长期维护。
我持续输出和沉淀前端领域的实战经验,日常关注并分享的技术方向包括 前端工程化、小程序、React / RN、Flutter、跨端方案,
在复杂业务落地、组件抽象、性能优化以及多端协作方面积累了大量真实项目经验。
技术方向: 前端 / 跨端 / 小程序 / 移动端工程化 内容平台: 掘金、知乎、CSDN、简书 创作特点: 实战导向、源码拆解、少空谈多落地 **文章状态:**长期稳定更新,大量原创输出
我的内容主要围绕 前端技术实战、真实业务踩坑总结、框架与方案选型思考、行业趋势解读 展开。文章不会停留在"API 怎么用",而是更关注为什么这么设计、在什么场景下容易踩坑、真实项目中如何取舍,希望能帮你在实际工作中少走弯路。
子玥酱 · 前端成长记录官 ✨
👋 如果你正在做前端,或准备长期走前端这条路
📚 关注我,第一时间获取前端行业趋势与实践总结
🎁 可领取 11 类前端进阶学习资源 (工程化 / 框架 / 跨端 / 面试 / 架构)
💡 一起把技术学"明白",也用"到位"
持续写作,持续进阶。
愿我们都能在代码和生活里,走得更稳一点 🌱
文章目录
-
- 引言
- 一个必须先接受的前提
- [第一类:Ability 被重建,而不是"异常退出"](#第一类:Ability 被重建,而不是“异常退出”)
- 第二类:前后台切换时,状态不同步
- 第三类:输入事件的丢失与延迟
-
- [错误模型:输入 = 状态变更](#错误模型:输入 = 状态变更)
- 正确模型:输入是"意图提示"
- 第四类:短时间的帧抖动与调度延迟
-
- [错误做法:假设 deltaTime 稳定](#错误做法:假设 deltaTime 稳定)
- 正确做法:引入"上限与收敛"
- 第五类:生命周期顺序"异常"
- 那什么才是真正的"异常"?
- 总结
引言
如果你已经意识到一件事:
HarmonyOS 上有些 Bug 永远修不好
那接下来绕不开的,就是更反直觉的一步:
有些"异常",你不仅修不好,还不该修。
不是因为你技术不够,而是因为------系统允许它发生。
一个必须先接受的前提
在 HarmonyOS 的游戏运行模型里:
稳定 ≠ 不变化
系统的目标,从来不是"让你的游戏状态永远保持一致",而是:
- 可调度
- 可回收
- 可恢复
- 对全局资源友好
这意味着:
局部异常,是换取整体稳定的成本。
第一类:Ability 被重建,而不是"异常退出"
很多开发者会把这种情况当成严重 Bug,但在 HarmonyOS 语义里,这其实是:
一次合法的 Ability 重建。
错误但常见的写法
ts
// 典型反模式
onDestroy() {
GlobalGameState.cache(this.runtime)
}
问题在于:
runtime里包含输入、动画、资源句柄- 这些对象 不保证下次仍然合法
- 你只是把"不稳定状态"延后引爆
正确做法:只保存"锚点状态"
ts
onDestroy() {
PersistentStore.saveSession({
levelId: this.session.levelId,
checkpointId: this.session.checkpointId,
playerStats: this.session.playerStats
})
}
然后在 onCreate 中:
ts
onCreate() {
const session = PersistentStore.loadSession()
this.runtime = new RuntimeContext(session)
}
重建 ≠ 恢复旧对象
重建 = 基于可信锚点重新推导
第二类:前后台切换时,状态不同步
你以为 onForeground 就等于"可以继续玩",但实际上:
Foreground ≠ 可交互
错误写法:把前台当成"继续信号"
ts
// 容易导致幽灵继续
onForeground() {
game.resume()
}
正确写法:引入"可交互判定层"
ts
onForeground() {
this.markForeground()
}
onWindowFocusChanged(hasFocus: boolean) {
if (hasFocus) {
game.enterPlayableState()
} else {
game.enterSuspendedState()
}
}
也就是说:
- Ability 只是"存在"
- 焦点 + 输入可用,才是"可玩"
中间那段不一致时间,是允许存在的。
第三类:输入事件的丢失与延迟
输入事件本来就不是必达的。
错误模型:输入 = 状态变更
ts
// 假设输入一定到达
onKeyDown(key) {
player.jump()
}
一旦这个 keyDown 被系统吞掉:
- 状态就永久不一致
正确模型:输入是"意图提示"
ts
onKeyDown(key) {
inputIntent.markJumpRequested()
}
在主循环中:
ts
update() {
if (inputIntent.shouldJump() && player.canJump()) {
player.jump()
}
inputIntent.clear()
}
关键点只有一句话:
没有输入,不是异常;输入被丢,逻辑也必须自洽。
第四类:短时间的帧抖动与调度延迟
"偶发不准时"是被接受的。
错误做法:假设 deltaTime 稳定
ts
// 帧依赖型逻辑
position += speed * deltaTime
comboTimer -= deltaTime
一旦某一帧被延迟:
- 位移突变
- 计时错乱
正确做法:引入"上限与收敛"
ts
const safeDelta = Math.min(deltaTime, 50)
position += speed * safeDelta
comboTimer = Math.max(comboTimer - safeDelta, 0)
甚至更激进一点:
ts
if (deltaTime > 100) {
resetTransientStates()
}
这不是性能优化,是对系统调度不确定性的尊重。
第五类:生命周期顺序"异常"
生命周期回调不是流程,而是信号。
错误心智模型
ts
// 假设一一对应
onBackground() {
save()
}
onForeground() {
restore()
}
一旦顺序不完整:
- 状态错配
- 重复恢复
正确模型:生命周期只触发"状态标记"
ts
onBackground() {
lifecycle.markBackground()
}
onDestroy() {
lifecycle.markDead()
}
真正的行为统一收敛到:
ts
update() {
if (lifecycle.shouldSuspend()) {
game.enterSafeState()
}
}
回调不是"命令",只是"环境变化提示"。
那什么才是真正的"异常"?
在 HarmonyOS 游戏里,真正需要修的,只有三类问题:
- 状态无法恢复
- 行为不可预测
- 异常会持续放大
一个非常工程化的判断代码可以是:
ts
if (error.isTransient && error.canRecover) {
accept()
} else {
fix()
}
总结
很多开发者在 HarmonyOS 上调游戏,最大的误区是:
把"系统边界"当成"代码缺陷"。
但真正成熟的运行态设计,是:
- 接受系统会打断你
- 接受状态会被清空
- 接受输入不可靠
- 接受调度不可控
然后在这些前提下:
把游戏设计成"能活下来的形态"。