Synchronous code runs line by line, each statement blocking the next until it completes. Asynchronous code starts an operation and continues without waiting, handling the result later via callbacks, promises, or async/await.
JavaScript is single-threaded: it has one call stack and can do one thing at a time. Long synchronous work (a huge loop) blocks everything — the UI freezes, no other code runs. Asynchronous operations (network requests, timers, file I/O) are handed off to the environment (browser/Node APIs); JavaScript keeps running, and when the operation finishes its callback is queued and later run by the event loop. This is how single-threaded JS stays responsive. Understanding the distinction explains why you cannot 'return' an async result synchronously and why await exists — to write async code in a readable, sequential-looking way without blocking the thread.
In a test, reading a file synchronously (fs.readFileSync) blocks until done, which is fine in setup; but making 100 network calls synchronously would be impossibly slow. Asynchronous calls let all 100 run concurrently while the event loop coordinates their responses.
Why does const data = fetchData(); console.log(data) log a Promise (or undefined) instead of the fetched data, and how do you get the actual data?