Review
A JavaScript program is (practically) always broken up into two or more chunks, where the first chunk runs now and the next chunk runs later, in response to an event. Even though the program is executed chunk-by-chunk, all of them share the same access to the program scope and state, so each modification to state is made on top of the previous state.
Whenever there are events to run, the event loop runs until the queue is empty. Each iteration of the event loop is a “tick.” User interaction, IO, and timers enqueue events on the event queue.
At any given moment, only one event can be processed from the queue at a time. While an event is executing, it can directly or indirectly cause one or more subsequent events.
Concurrency is when two or more chains of events interleave over time, such that from a high-level perspective, they appear to be running simultaneously (even though at any given moment only one event is being processed).
It’s often necessary to do some form of interaction coordination between these concurrent “processes” (as distinct from operating system processes), for instance to ensure ordering or to prevent “race conditions.” These “processes” can also cooperate by breaking themselves into smaller chunks and to allow other “process” interleaving.