JavaScript11 min read

JavaScript Promises: Handling Async Operations

Master JavaScript Promises. Understand async operations, promise chaining, error handling, and Promise.all.

Alex Thompson
December 19, 2025
0.0k0

JavaScript Promises

The Problem: Things That Take Time

Imagine you order food online. You don't stand at the door waiting - you do other things, and when the food arrives, you handle it.

JavaScript works the same way. Some things take time:

``` ┌─────────────────────┐ │ You: Fetch data │ │ from API │ │ (takes 2 seconds) │ └──────────┬──────────┘ │ ┌───────────▼───────────┐ │ JavaScript doesn't │ │ wait! It continues │ │ with other code │ └───────────────────────┘ │ ┌───────────▼───────────┐ │ 2 seconds later... │ │ API responds │ │ Now what? │ └───────────────────────┘ ```

The problem: How do you handle the response when it arrives? Promises solve this.

What is a Promise?

A Promise is like a receipt. You get it immediately, but the actual result comes later.

``` Promise Lifecycle: ┌─────────────────────┐ │ 1. Pending │ ← Just created, waiting │ (Waiting...) │ └──────────┬──────────┘ │ ┌───────┴───────┐ │ │ ┌───▼───┐ ┌───▼───┐ │ 2. │ │ 3. │ │Fulfilled│ │Rejected│ │(Success)│ │(Error) │ └────────┘ └───────┘ ```

**Three states:** - **Pending:** Waiting for result - **Fulfilled:** Got the result (success) - **Rejected:** Something went wrong (error)

Step-by-Step: Creating a Promise

**Step 1:** Create a new Promise ```javascript const myPromise = new Promise((resolve, reject) => { }); ```

**Step 2:** Add your async operation ```javascript const myPromise = new Promise((resolve, reject) => { setTimeout(() => { // This runs after 1 second }, 1000); }); ```

**Step 3:** Call resolve on success ```javascript const myPromise = new Promise((resolve, reject) => { setTimeout(() => { resolve('Data loaded!'); }, 1000); }); ```

**Step 4:** Call reject on error ```javascript const myPromise = new Promise((resolve, reject) => { setTimeout(() => { const success = true; if (success) { resolve('Success!'); } else { reject('Failed!'); } }, 1000); }); ```

Step-by-Step: Using a Promise

**Step 1:** Call .then() for success ```javascript myPromise.then(result => { console.log(result); // "Success!" }); ```

**Step 2:** Add .catch() for errors ```javascript myPromise .then(result => { console.log(result); }) .catch(error => { console.error(error); }); ```

**What happens:** ``` 1. Promise starts (Pending) │ 2. After 1 second... │ 3. If success → .then() runs If error → .catch() runs ```

Promise Chaining: One After Another

Sometimes you need to do things in order:

```javascript fetch('https://api.example.com/user') .then(response => response.json()) .then(user => { console.log('Got user:', user); return fetch(`https://api.example.com/posts/${user.id}`); }) .then(response => response.json()) .then(posts => { console.log('Got posts:', posts); }) .catch(error => { console.error('Something failed:', error); }); ```

**Flow diagram:** ``` Step 1: Fetch user │ ▼ Step 2: Convert to JSON │ ▼ Step 3: Get user ID, fetch posts │ ▼ Step 4: Convert posts to JSON │ ▼ Step 5: Use the posts ```

Each `.then()` waits for the previous one to finish.

Promise.all: Do Multiple Things at Once

When you need to wait for multiple things:

```javascript Promise.all([ fetch('/api/users'), fetch('/api/posts'), fetch('/api/comments') ]) .then(([users, posts, comments]) => { console.log('All done!'); console.log('Users:', users); console.log('Posts:', posts); console.log('Comments:', comments); }) .catch(error => { console.error('One of them failed:', error); }); ```

**How it works:** ``` ┌─────────────┐ │ Start all │ │ 3 requests │ └──────┬──────┘ │ ┌───┴───┐ │ │ │ ┌──▼──┐ ┌──▼──┐ ┌──▼──┐ │User │ │Post │ │Comm │ │API │ │API │ │API │ └──┬──┘ └──┬──┘ └──┬──┘ │ │ │ └───┬───┴───┬───┘ │ │ ┌───────▼───────▼───────┐ │ Wait for ALL │ │ to finish │ └───────────────────────┘ │ ┌───────▼───────┐ │ Then run code│ └───────────────┘ ```

**Important:** If any promise fails, the whole thing fails.

Real Example: Loading User Data

```javascript function loadUserData(userId) { return fetch(`/api/users/${userId}`) .then(response => { if (!response.ok) { throw new Error('User not found'); } return response.json(); }) .then(user => { console.log('User loaded:', user.name); return user; }) .catch(error => { console.error('Failed to load user:', error); throw error; }); }

// Use it loadUserData(123) .then(user => { console.log('Got user:', user); }); ```

Common Patterns

**Pattern 1: Handle errors properly** ```javascript promise .then(result => { // Success }) .catch(error => { // Always handle errors! console.error(error); }); ```

**Pattern 2: Return promises in .then()** ```javascript fetch('/api/data') .then(response => response.json()) .then(data => { return fetch(`/api/more/${data.id}`); // Return next promise }) .then(response => response.json()); ```

Quick Tips

1. **Always handle errors** - Use .catch() or your app might break silently 2. **Return promises in .then()** - This lets you chain them 3. **Use Promise.all for parallel operations** - Faster than doing them one by one 4. **Promises are everywhere** - fetch(), setTimeout(), file operations all return promises

Promises are essential for modern JavaScript. They let you handle async operations cleanly. Once you understand promises, async/await will make much more sense.

#JavaScript#Promises#Async#Intermediate