JavaScript Async Programming
# JavaScript Async Programming
JavaScript is a single-threaded language. This means it can only do one thing at a time. If it had to pause and wait 5 seconds for a server response to download, your entire browser would freeze for 5 seconds. You wouldn't be able to click, type, or scroll.
To solve this, JavaScript uses Asynchronous Programming. It hands the slow tasks (like fetching data or running timers) off to the browser, continues running the rest of the code, and then deals with the slow tasks when they finish.
1. Introduction
Historically, developers handled async tasks using Callbacks (passing a function into another function to run later). This led to "Callback Hell"—a massive, unreadable pyramid of nested functions.
ES6 introduced Promises (which we saw in Chapter 24 with fetch).
ES8 (2017) introduced Async/Await, which is syntactic sugar over Promises that makes asynchronous code look and behave exactly like synchronous, top-to-bottom code.
2. Learning Objectives
By the end of this chapter, you will be able to:
- Understand the difference between Synchronous and Asynchronous execution.
- Create and consume a Promise.
-
Use
asyncandawaitto write clean asynchronous code.
-
Handle errors in async functions using
try...catch.
- Build an Async User Loader mini-project.
3. The Callback Problem
Let's look at why Promises and Async/Await were invented. If you needed to do three slow things in a row using callbacks, it looked like this:
This is unreadable and incredibly difficult to debug if an error occurs.
4. Promises Review
A Promise is an object representing a future result. We handle it using .then() for success and .catch() for errors.
This is much better, but there is still an even cleaner way.
---
5. Async / Await Syntax
async and await allow you to write Promise-based code as if it were synchronous.
-
1.
async: You put this keyword in front of a function declaration. It tells JavaScript: "This function will contain asynchronous operations. It will automatically return a Promise."
-
2.
await: You put this keyword in front of a Promise (likefetch). It tells JavaScript: "Pause the execution of this specific function right here until the Promise finishes. Do not move to the next line until you have the data."
6. Real-world Examples & Code Snippets
Example 1: Basic Async / Await
Let's rewrite a basic fetch request using modern syntax.
Example 2: Error Handling with Try/Catch
Because we are no longer using .catch(), how do we handle errors? We wrap the await code inside a standard try...catch block (from Chapter 26!).
*This is the gold standard for modern API calls.*
Example 3: Multiple Awaits (Sequential)
If tasks rely on each other, you await them one by one.
Example 4: Promise.all() (Concurrent)
If you have multiple asynchronous tasks that DO NOT rely on each other, awaiting them one-by-one is slow. Use Promise.all() to run them all at the exact same time.
Example 5: Creating Your Own Promise
Sometimes you need to convert older, callback-based code (like setTimeout) into a Promise so you can await it.
---
7. Common Mistakes for Beginners
-
1.
Using
awaitoutside of anasyncfunction: You cannot writeconst data = await fetch(...)directly in the global scope of a standard script file. It MUST be inside a function labeledasync. *(Note: ES2022 introduced "Top-level await" for ES Modules, but as a beginner, always wrap it in an async function).*
-
2.
Forgetting
await: If you writeconst res = fetch(url);withoutawait,reswill hold the literal "Promise" object, not the data. Trying to runres.json()will crash.
-
3.
Sequential awaiting for independent data: If you need to load users, posts, and comments that are completely independent, doing three sequential
awaits takes 3x as long. UsePromise.all().
8. Best Practices
-
Always prefer
async / awaitover.then() / .catch(). It makes the code vastly easier to read, trace, and debug.
-
Always wrap
awaitcalls in atry...catchblock. Network requests fail constantly in the real world.
9. Mini Project: Async User Loader
Let's build a UI that loads a random user from a public API, with a simulated loading state, using async/await and try...catch.
HTML:
async.js:
10. Exercises
-
1.
Change this Promise chain into an
async/awaitfunction:
javascript
function getData() {
fetch('api/data')
.then(res => res.json())
.then(data => console.log(data));
}
`
-
2.
Wrap your new
async function inside a try...catch block.
-
3.
What happens if you use the
await keyword inside a normal function (a function without the async prefix)?
11. MCQs (Multiple Choice Questions)
Q1: What must be placed in front of a function declaration to allow the use of
await inside it?
A) promise
B) defer
C) async
D) yield
*Answer: C*
Q2: What does the
await keyword do?
A) Cancels a Promise.
B) Pauses the execution of the async function until the Promise is resolved or rejected.
C) Puts the browser to sleep.
D) Makes a synchronous function asynchronous.
*Answer: B*
Q3: Which block is used to catch errors in an
async/await setup?
A) .catch()
B) try...catch
C) if (error)
D) errorHandler
*Answer: B*
12. Interview Questions
Q: Can you use
await with a function that does NOT return a Promise?
*A: Yes. If you await a non-Promise value (like await 5), JavaScript automatically wraps it in a resolved Promise. It effectively does nothing, but it will not crash.*
Q: Explain how
async/await is syntactic sugar.
*A: Under the hood, JavaScript does not execute async/await sequentially. The engine transforms async/await code back into standard Promises and .then() chains before executing it. It just makes the code read sequentially for the human developer.*
13. Summary
-
Asynchronous programming prevents the browser from freezing during slow tasks.
-
async marks a function as asynchronous.
-
await pauses that function until a Promise (like fetch) resolves.
-
async/await replaces messy .then() chains.
-
Always use
try...catch to handle async errors.
-
Use
Promise.all()` to run independent tasks concurrently.