It might be a bit esoteric but you can think of Pulumi as a “graph executor” - it receives a graph of your desired state, turns that graph into a set of concrete steps that need to be completed, and then executes them all in order, possibly in parallel.
Since Pulumi lets you inspect the outputs of resources that are getting created as part of this graph execution, it’s naturally the case that the ouptuts of a resources resolve asynchronously, as resources get created and Pulumi advances the execution of the graph. The asynchrony mirrors data flow dependencies between resources, and really when you’re writing a Pulumi program what you’re doing is connecting together different asynchronous streams of data.
It’s confusing when these things don’t happen synchronously, but doing things asynchronously lets us present a facade of an imperative object model on top of a declarative, asynchronous data model.