Skip to content

Lesson 008|onLoad、start、update 到底什么时候执行?

Tags: #Creator2.x #Component #Lifecycle #Update #EventDifficulty: ⭐⭐☆☆☆


🎯 本课目标

  • 理解 Component 生命周期
  • 理解 onLoad、onEnable、start、update、onDisable、onDestroy 的职责
  • 理解 onLoad 和 start 的区别
  • 理解为什么空 update 也有成本
  • 理解事件注册和取消的正确时机

🧩 上节课回顾

上一课我们讲了 Node + Component 架构。

Component 一个重要特点是:

它有生命周期。

你每天写的:

ts
onLoad() {}
start() {}
update(dt) {}
onEnable() {}
onDisable() {}
onDestroy() {}

都属于 Component 生命周期。


💡 生命周期是什么?

生命周期可以理解成:

引擎在不同时间点自动调用你的函数。

常见流程:

text
节点 / 组件被创建

onLoad

节点激活

onEnable

第一帧 update 前

start

每一帧

update

组件或节点被禁用

onDisable

节点被销毁

onDestroy

🧠 onLoad

onLoad 可以理解成:

组件初始化时调用。

常用于:

text
获取节点引用
初始化变量
绑定固定引用
读取配置
建立组件之间的关系

例如:

ts
onLoad() {
    this.icon = this.node.getChildByName("Icon");
    this.button = this.node.getComponent(cc.Button);
}

🧠 start

start 可以理解成:

第一次 update 之前调用。

onLoad 更早,start 更晚。

有时候你需要等所有组件都 onLoad 完,再做某些逻辑,这时 start 更合适。


🧠 update

update(dt) 是每帧调用。

例如:

ts
update(dt) {
    this.node.x += 100 * dt;
}

dt 是上一帧到这一帧经过的时间。

如果游戏 60 FPS:

text
dt ≈ 0.016

所以移动常写:

ts
this.node.x += speed * dt;

而不是:

ts
this.node.x += speed;

因为后者会受帧率影响。


🧠 onEnable 和 onDisable

onEnable

组件进入启用状态时调用。

常用于注册事件:

ts
onEnable() {
    this.node.on(cc.Node.EventType.TOUCH_END, this.onClick, this);
}

onDisable

组件退出启用状态时调用。

常用于取消事件:

ts
onDisable() {
    this.node.off(cc.Node.EventType.TOUCH_END, this.onClick, this);
}

重要习惯:

onEnable 注册的事件,优先在 onDisable 取消。


🧠 onDestroy

onDestroy 是组件销毁时调用。

常用于:

text
释放资源
清理引用
取消定时器
取消全局事件监听
取消网络回调

尤其是全局事件、网络回调、定时器,如果不清理,可能导致对象销毁后仍然被回调。


🔍 常见执行顺序

text
onLoad

onEnable

start

update / lateUpdate

onDisable

onDestroy

其中:

text
onLoad:初始化
onEnable:开始启用
start:第一次 update 前
update:每帧逻辑
lateUpdate:每帧后半段逻辑
onDisable:停止启用
onDestroy:销毁清理

🔍 onLoad 和 start 怎么选?

放在 onLoad

text
获取自身节点引用
初始化字段
绑定固定引用
准备基础数据

放在 start

text
依赖其他组件已经初始化
依赖场景中其他节点 onLoad 完成
第一次显示前执行逻辑

🧠 为什么空 update 也有成本?

只要组件实现了:

ts
update(dt) {
}

引擎就可能把它加入每帧调度列表。

即使函数是空的,也有成本:

text
调度列表记录
每帧遍历
enabled / activeInHierarchy 判断
函数调用

所以:

不用 update,就不要写空 update。


💼 工作中的真实案例

事件重复绑定

如果写了:

ts
onEnable() {
    this.node.on("click", this.onClick, this);
}

但没有:

ts
onDisable() {
    this.node.off("click", this.onClick, this);
}

节点反复 active true / false 后,可能导致事件重复绑定。

结果可能是:

text
点一次按钮,回调执行多次

⚠️ 常见误区

  • onLoad 和 start 不应该随便混用。
  • 空 update 也有成本。
  • 事件注册后要考虑取消。
  • active = false 不只是隐藏,也会触发 onDisable,影响 update、事件响应和子节点激活状态。

🎤 面试会怎么问

onLoad 和 start 有什么区别?

onLoad 在组件初始化时调用,通常用于初始化自身引用和变量;start 在第一次 update 之前调用,通常用于依赖其他组件 onLoad 完成后的逻辑。

enabled = false 会触发什么?

组件从启用状态切到禁用状态时,会触发 onDisable;如果之后重新 enabled = true,并且节点处于 activeInHierarchy 状态,会触发 onEnable。

为什么不建议写空 update?

只要组件实现了 update,引擎就可能把它加入每帧调度列表。即使函数为空,也会有调度、遍历、状态判断和函数调用成本。

onEnable 注册事件,应该在哪里取消?

通常应该在 onDisable 中取消。onDestroy 可以做最终兜底清理,特别是全局事件、网络回调和定时器。


📝 今日练习参考答案

  1. 正常顺序:
text
onLoad

onEnable

start

update / lateUpdate 每帧执行

onDisable

onDestroy
  1. 如果节点 active = false,通常触发 onDisable,并停止 update、事件响应和渲染相关逻辑。

  2. 如果组件 enabled = false,通常也会触发 onDisable。区别是:

    • node.active = false:影响整个节点和子树
    • component.enabled = false:只影响这个组件
  3. 空 update 也会被每帧调度和调用,有成本。

  4. onEnable 注册事件,通常应该在 onDisable 取消事件。onDestroy 可以做兜底清理。


🚀 能力成长

学完本课后,你应该能:

  • 解释 Component 生命周期
  • 区分 onLoad 和 start
  • 解释 update 的调度成本
  • 正确处理事件注册与取消
  • 初步分析生命周期导致的重复事件、内存泄漏和性能问题

✅ 本课总结

text
onLoad:初始化自身。
onEnable:组件进入启用状态。
start:第一次 update 前。
update:每帧执行。
onDisable:组件退出启用状态。
onDestroy:销毁清理。

工程习惯:

text
onEnable 注册的事件,优先在 onDisable 取消。
不用 update,就不要写空 update。

下一课: active、enabled、destroy 的区别