As I mentioned in the comments, a simple way to investigate execution order in Unity is to add a debug log to each method you're interested in, something like...
Debug.LogFormat("{0}: [Event] called on {1}'s {2} at {3}",
Time.frameCount,
name,
this.GetType().Name,
Time.time);
Then you can read the sequence of messages and frame time stamps in the log to find out exactly what order each method was called in.
You'll find that this varies between objects that already existed, enabled in your scene from the beginning of the frame, and new objects that get created or enabled midway through the frame.
For script instances already present in your scene, at load:
Each script instance gets its Awake
method called, then its OnEnable
method, if enabled, back-to-back. Then then the next script instance gets its Awake
called, so you'll see an alternating pattern of Awake
OnOnable
Awake
OnEnable
if you log it as I recommended.
This is why these two methods are shown bundled together as "Initialization" in the Unity execution order diagram.
Then all the Start
methods are called, on all script instances.
Then all the FixedUpdate
methods for the first physics step.
Then all the Update
methods for the variable time step.
Then all the LateUpdate
methods.
For subsequent frames, this process repeats for all enabled objects remaining from previous frames, starting from step 3 if there's one or more physics steps to evaluate this frame, and otherwise skipping ahead to step 4.
In my tests, the order in which particular script instances get their message method called within any given step appears to be the reverse order of creation, with the components I added last getting their method called first. I wouldn't count on this level of micro-ordering for your scripts though, as it's something the engine could be expected to change when optimizing a build.
This means the order can hop back-and-forth between GameObjects in the hierarchy, and does not necessarily process all script instances on a single object consecutively, before scripts on its child objects, etc. (This is to be expected, since we can override the order of executing particular script classes independent of how they're arranged on objects in the scene).
If a new script instance is spawned mid-frame, with Instantiate
or AddComponent
:
Its Awake
and OnEnable
(if enabled) methods get called back-to-back.
The Instantiate
or AddComponent
call returns, and control flow resumes on the next statement of the method that spawned the script, and the engine continues processing whatever message it was processing at the time.
The engine moves on to the next update step (FixedUpdate
, Update
, LateUpdate
, etc.)
That means the new script instance has "missed the bus" for the current processing step, but can still catch the next one after this. If it was spawned during Update
, it doesn't get an Update
call this frame. But it could still get a LateUpdate
.
When the new script instance's turn comes in the next processing step (ie. FixedUpdate
/Update
/LateUpdate
), Unity checks to see if it's been started yet. If not, it calls Start
on this instance "just in time," then proceeds with processing its message method call.
Just before rendering, if any newly-spawned scripts still haven't started (eg. they were spawned in LateUpdate
), Unity calls Start
on those stragglers.
So, these newly-created or newly-enabled objects could be the reason you're observing Start
or other messages sometimes getting called in the middle of some other phase of processing. It's the engine playing catch-up to get the newly-added or -awoken instance up to speed for wherever the rest of the scene objects have advanced to in the update order.
Debug.LogFormat("Component {0} on object {1} had its [Event] method called", this.GetType(), name);
in each method you want to check, replacing[Event]
with the name of that event message. Then look at the order these print in your log. \$\endgroup\$