godotengine / godotengine/godot-docs
Document the exact order of all lifetime signals/callbacks/notifications
- Dominant language
- reStructuredText
- Stars
- 5.7k
- Forks
- 3.8k
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 25
Description
**Your Godot version:**
3.4.1
**Issue description:**
From time to time, I keep seeing people confused about order of lifetime methods. Recently there was a bug report, where it turned out that the user tried to access an `onready` variable inside a callback from signal emitted in `_ready()` of a child node. It's convoluted, but the `onready` variable wasn't initialized in parent, because child nodes will call their `_ready()` first.
We do have some docs about order of some methods, but there isn't any comprehensive guide that lists all callbacks/notifications etc and order of variable initialization.
I made a small test project. For a single node the order is this:
- **variables are initialized**
- `_init()` callback
- **exported variables are initialized**
- `NOTIFICATION_ENTER_TREE`
- `_enter_tree()` callback
- `tree_entered` signal
- `NOTIFICATION_POST_ENTER_TREE`
- **onready variables are initialized**
- `_ready()` callback
- `NOTIFICATION_READY`
- `ready` signal
It gets super-complicated when node has children. My test scene was like this:

Tested with this script, that prints about everything for when node is created and destroyed:
```GDScript
extends Node
func _init() -> void:
prints(self, "_init() callback")
connect("tree_entered", self, "on_tree_entered")
connect("ready", self, "on_ready")
connect("tree_exiting", self, "on_tree_exiting")
connect("tree_exited", self, "on_tree_exited")
func _enter_tree() -> void:
prints(name, "_enter_tree() callback")
func _ready() -> void:
prints(name, "_ready() callback")
if get_parent() == get_tree().root:
queue_free()
func _exit_tree() -> void:
prints(name, "_exit_tree() callback")
func _notification(what: int) -> void:
match what:
NOTIFICATION_ENTER_TREE:
prints(name, "NOTIFICATION_ENTER_TREE")
NOTIFICATION_EXIT_TREE:
prints(name, "NOTIFICATION_EXIT_TREE")
NOTIFICATION_READY:
prints(name, "NOTIFICATION_READY")
NOTIFICATION_PREDELETE:
prints(name, "NOTIFICATION_PREDELETE")
NOTIFICATION_POSTINITIALIZE:
prints(name, "NOTIFICATION_POSTINITIALIZE")
NOTIFICATION_POST_ENTER_TREE:
prints(name, "NOTIFICATION_POST_ENTER_TREE")
func on_tree_entered():
prints(name, "tree_entered signal")
func on_ready():
prints(name, "ready signal")
func on_tree_exiting():
prints(name, "tree_exiting signal")
func on_tree_exited():
prints(name, "tree_exited signal")
```
And the result:
```
--- entering
[Node:1254] _init() callback
[Spatial:1255] _init() callback
[Control:1256] _init() callback
[Node2D:1257] _init() callback
[CanvasLayer:1258] _init() callback
[HTTPRequest:1259] _init() callback
[ResourcePreloader:1264] _init() callback
A-- NOTIFICATION_ENTER_TREE
A-- _enter_tree() callback
A-- tree_entered signal
AA- NOTIFICATION_ENTER_TREE
AA- _enter_tree() callback
AA- tree_entered signal
AAA NOTIFICATION_ENTER_TREE
AAA _enter_tree() callback
AAA tree_entered signal
AAB NOTIFICATION_ENTER_TREE
AAB _enter_tree() callback
AAB tree_entered signal
AB- NOTIFICATION_ENTER_TREE
AB- _enter_tree() callback
AB- tree_entered signal
ABA NOTIFICATION_ENTER_TREE
ABA _enter_tree() callback
ABA tree_entered signal
ABB NOTIFICATION_ENTER_TREE
ABB _enter_tree() callback
ABB tree_entered signal
AAA NOTIFICATION_POST_ENTER_TREE
AAA _ready() callback
AAA NOTIFICATION_READY
AAA ready signal
AAB NOTIFICATION_POST_ENTER_TREE
AAB _ready() callback
AAB NOTIFICATION_READY
AAB ready signal
AA- NOTIFICATION_POST_ENTER_TREE
AA- _ready() callback
AA- NOTIFICATION_READY
AA- ready signal
ABA NOTIFICATION_POST_ENTER_TREE
ABA _ready() callback
ABA NOTIFICATION_READY
ABA ready signal
ABB NOTIFICATION_POST_ENTER_TREE
ABB _ready() callback
ABB NOTIFICATION_READY
ABB ready signal
AB- NOTIFICATION_POST_ENTER_TREE
AB- _ready() callback
AB- NOTIFICATION_READY
AB- ready signal
A-- NOTIFICATION_POST_ENTER_TREE
A-- _ready() callback
A-- NOTIFICATION_READY
A-- ready signal
--- exiting
ABB _exit_tree() callback
ABB tree_exiting signal
ABB NOTIFICATION_EXIT_TREE
ABA _exit_tree() callback
ABA tree_exiting signal
ABA NOTIFICATION_EXIT_TREE
AB- _exit_tree() callback
AB- tree_exiting signal
AB- NOTIFICATION_EXIT_TREE
AAB _exit_tree() callback
AAB tree_exiting signal
AAB NOTIFICATION_EXIT_TREE
AAA _exit_tree() callback
AAA tree_exiting signal
AAA NOTIFICATION_EXIT_TREE
AA- _exit_tree() callback
AA- tree_exiting signal
AA- NOTIFICATION_EXIT_TREE
A-- _exit_tree() callback
A-- tree_exiting signal
A-- NOTIFICATION_EXIT_TREE
AAA tree_exited signal
AAB tree_exited signal
AA- tree_exited signal
ABA tree_exited signal
ABB tree_exited signal
AB- tree_exited signal
A-- tree_exited signal
ABB NOTIFICATION_PREDELETE
ABA NOTIFICATION_PREDELETE
AB- NOTIFICATION_PREDELETE
AAB NOTIFICATION_PREDELETE
AAA NOTIFICATION_PREDELETE
AA- NOTIFICATION_PREDELETE
A-- NOTIFICATION_PREDELETE
```
Interesting/not expected stuff:
- `_init()` is called for every node in scene before any other method and before any is added to tree
- `enter_tree` is called in the same order as init, i.e. depth-first
- `NOTIFICATION_POST_ENTER_TREE` happens right before `_ready()` callback in any node, but `onready` variables aren't initialized yet
- which means that `_ready()` is the earliest place where you can use `onready` variables and initialization of `onready` variables has the same order as `_ready()` callback
- ready and enter tree have reverse order of things. For enter tree, the notification comes first, while it's the opposite for ready
- `tree_exiting` is emitted first in children, same as `NOTIFICATION_PREDELETE`, but `tree_exited` is the opposite; parents emit it first.
- thus `tree_exiting` is "equivalent" of `ready` and `tree_exited` is "equivalent" of `enter_tree`, but they are reversed, i.e. when destroying nodes it's as if "ready" came first instead of last
That's lots of information, not sure how much of it is really useful, but it would be nice to have it documented somewhere. Knowing the exact order of things in tree might come in handy for some complicated scene logic and might save some confusion when things don't get called in the order you'd expect.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.