The way any environment works, simplified, is by going through a stack of tasks. Whenever the user moves the mouse, or
XMLHttpRequest fetches, new tasks are queued to eventually dispatch events and then run event handlers and listeners. Asynchronous steps run in parallel with this.
When new standards are written, this is often done wrong. A set of asynchronous steps cannot refer to global state that might change, such as a document's base URL. They also cannot change state, such as properties on an object. Remember, these steps run in parallel, so if you change
obj.prop === obj.prop would no longer be guaranteed. Bad. Instead you queue a task. Effectively scheduling some code to run in the environment at some point in the future when it has the bandwidth. The Fetch layer queues tasks whenever new network chunks arrive. The UI layer queues tasks whenever the user moves the mouse. Etc.
(Not all of this is properly defined as of yet, please fill in the gaps as you run across them. Note Asynchronous Steps Explicitly has advice for how to go about that.)