Is there a prediactable execution order for Start() given a list of Components?

As an experiment, I’m trying to determine how Start() is called in MonoBehaviours and when it’s execution happens. I have in my hierarchy 3 Game Objects with the same two scripts: Initialize and Disable On Start.
Initialize does some initialization at Start() (Debug.Log), and Disable On Start does what it says; it disables the Game Object on Start(). I’ve determine that the call order for Start() happens in the hierachy from top to bottom and traverses nested objects. That much I figuered out.

What I can’t figure out is the execution order for scripts on a single Game Object. Lets say I want a Game Object to start in the scene disabled but not before it can initialize itself. So I have a script that does initialization, and then at the bottom of the component list I have a final Disable On Start script that disables the self Game Object. I’d assume the same top-down call behaviour as in the hierachy, but that doesn’t seem to be the case. I tried bottom-up, but it doesn’t seem to matter where Disable On Start is in the component list. Disable On Start always disables the Game Object before Inilization can do it’s thing on Start().

Is Start() called sequentially according to the component list? Is Start() called asynchronously on each Component?

I thought maybe it was alphabetical order of the script name, so I tried renaming my Initialize script to “A”, but that didn’t yield resutls. Disable On Start was always being called first on each Game Object. I have no idea why or how, or if I can even control this execution order. Any thoughts?

Before you guys mention Awake() or Coroutines, I just need to say that I already know these things exist. I know I’m suppose to use Awake() for things that should happen before Start() and I can use Coroutines to delay execution, but that’s not what I’m trying to achieve with this experiment. The point of what I’m trying to do is to figure out how the execution order of Start() happens; given multple scripts on a single Game Object, and if I have any meaningfuly control over the execution order. The Game Object hierachy seems predictable, but not the component list.

Unity explicitly does not have a defined script execution order. Even if you observe a particular rule like “top to bottom” in the hierarchy, there is no guarantee that the same traversal order will happen on different hardware or a different version of Unity. You should not code your game to rely on any such execution order at all.
EXCEPT for one thing:

There is one official, documented way of enforcing a particular script execution order, and that is the Script Execution Order project settings:
https://docs.unity3d.com/Manual/class-MonoManager.html

There is also the similar, but undocumented DefaultExecutionOrder attribute, but since it’s undocumented I’d give it similar caveats to whatever rules you may have found via experimentation:
https://discussions.unity.com/t/701051

Start() is not called asynchronously on anything, unless you define your Start() method as a coroutine.

Personally, I just write all my code in such a way that script execution order doesn’t matter for 99% of things. For the remaining 1%, I use the Script Execution Order settings.

1 Like

I usually don’t rely on execution order to write Unity code, but it’s insanely helpfully to know. In instances where Object B has a dependency on Object A, and A needs to have completed it’s Start() in order for Object B to work at the time of B’s conception, and both of these objects are statically in the scene at the same time, controlling the execution order really matters. I run into this object dependency problem quite often.

In a large HoloLens project I worked on for commission, there is a game server it connects to, but it also needs to connect to MS Azure services for it’s Spatial Anchor system, and one absolutely had to come before the other. Game object initializaton had to wait for full initialization of one object, then continue. The solution I came up with was just to at runtime instantiate these objects in the scene at Start(), wait for an “Initilization Done” flag, then instantiate the next one.

1 Like

Yes it’s important to know, but it also can’t be relied on, at all, unless you’re using Script Execution Order. The way I handle this kind of dependency is to split up my initialization for any script into two parts:

  • Self initialization. This is things like GetComponent calls to establish references to components on my own object or child objects. It is also Instance = this; type calls for singletons

  • Initialization that depends on other objects: This is where I do anything that relies on other objects being fully initialized themselves. For example. using the .Instance static property of a singleton, or calling a method on another component.

If you break up your initialization into two phases like this, and do phase 1 in Awake() and phase 2 in Start(), everything works as intended, with no need to worry about which Start() or Awake() runs first. We know that two objects statically in the scene will both run Awake() before any Start()s are run at all, so this works.

2 Likes