Okay, so we understand that:
So how does the actual concurrency work? In the case of:
setTimeout(() => {
console.log("Hi I'm async!");
}, 1000);
What logic makes sure that the callback function isn't pushed into the task queue until 1000 milliseconds have passed? Or regarding an HTTP request, what logic pushed the network response into the task queue when the request is complete?
The answer is external APIs. Things like setTimeout, fetch, and addEventListener are all examples of external APIs that the browser or Node.js, Deno, or Bun provide.
The JavaScript runtime (your code and the JS engine) are single-threaded, but these external APIs are not! They are tasks that are fired off and in the background, and when they're done, their results are popped back into the task queue for the event loop to handle.