There is ever more asynchronicity within the web platform. Asynchronous being some set of steps that could be performed in parallel with JavaScript running in a given environment such as a window or worker. Fetching networked resources, computing crypto, and audio processing, are examples of things that can be done asynchronous. The JavaScript language does not really know about threading or background processing. The platform however has had this for a long time and synchronized with JavaScript using events and these days also through resolving promises.
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 === 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.
In summary, you have the environments where based on a sequence of tasks, JavaScript is executed. Then there is the background processing, known as asynchronous steps in standards, which queues new tasks to the various environments to stay synchronized over time.
(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.)