These are progressively nicer ways to express non-blocking work on a single thread, all driven underneath by an event loop that runs ready callbacks one at a time. They manage when code resumes, not multiple threads.
The event loop
A single-threaded loop maintains a queue of ready callbacks. When an async operation (timer, I/O) completes, its callback is enqueued; the loop picks the next one and runs it to completion, then repeats. Nothing preempts a running callback, so long CPU work blocks everything.
[event loop] → run callback → I/O finishes → enqueue callback → run next → ...
