Suggest an editImprove this articleRefine the answer for “Promises in JavaScript and promise methods”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Promise** is a JavaScript object representing the eventual result of an async operation. ```javascript const p = new Promise((resolve, reject) => { setTimeout(() => resolve("done"), 1000); }); p.then(console.log).catch(console.error); // "done" ``` **Key:** three states (pending, fulfilled, rejected). Once settled, a Promise never changes its state.Shown above the full answer for quick recall.Answer (EN)Image**Promise** is a JavaScript object that represents the eventual result of an asynchronous operation, either success or failure. ## Theory ### TL;DR - Analogy: ordering food delivery. You get a ticket (Promise) right away. Then food arrives (fulfilled) or you get a "sorry, out of stock" note (rejected). One answer, exactly once. - Main difference from callbacks: a Promise is one object you chain with `.then()`. Callbacks nest into each other, creating deeply indented, hard-to-follow code. - States are final: once a Promise settles (fulfilled or rejected), it never changes. - Method rules: `Promise.all()` when everything must succeed, `Promise.allSettled()` for partial success, `Promise.race()` for the fastest result, `Promise.any()` for the first success. ### Quick example ```javascript // Simulates an API call const fetchData = new Promise((resolve, reject) => { setTimeout(() => { const ok = Math.random() > 0.5; ok ? resolve("Data loaded") : reject("Network error"); }, 1000); }); // Consuming the Promise fetchData .then(result => console.log(result)) // "Data loaded" .catch(error => console.error(error)); // "Network error" ``` After 1 second, exactly one branch fires. The Promise settles once and stays there. ### Promise states A Promise is always in one of three states: - **Pending**: the async operation is still running, no result yet - **Fulfilled**: `resolve(value)` was called, operation succeeded - **Rejected**: `reject(error)` was called, operation failed Pending is the starting state. Fulfilled and rejected are terminal. Unlike browser events, a Promise fires exactly once and stays settled. ### Key difference from callbacks Callbacks nest. Every additional async step adds one more level of indentation, and error handling must happen at each level manually. A Promise chains: each `.then()` returns a new Promise, so you stay at one indentation level. Errors travel automatically to the nearest `.catch()`. That behavior removes callback hell for anything with more than one async step. ### Promise methods **Promise.all()** Runs all promises in parallel and waits for every one to fulfill. Returns an array of results in the same order as input. If any single promise rejects, the whole thing rejects immediately with that error. The other promises keep running, but their results are ignored. ```javascript const [user, posts] = await Promise.all([ fetch('/api/user/1').then(r => r.json()), fetch('/api/posts?userId=1').then(r => r.json()) ]); // Both requests fire at once; fails fast if either errors ``` Use this when all operations must succeed before continuing. **Promise.allSettled()** Same parallel execution as `Promise.all()`, but waits for every promise to finish regardless of outcome. Returns `{status: 'fulfilled', value: ...}` or `{status: 'rejected', reason: ...}` for each. ```javascript const results = await Promise.allSettled([fetchUser(), fetchPosts()]); const loaded = results .filter(r => r.status === 'fulfilled') .map(r => r.value); ``` Use this when partial success is acceptable, like a dashboard that renders whatever data actually loaded. **Promise.race()** Returns the first promise to settle, fulfilled or rejected. Everything else is discarded. The most common real use is a timeout wrapper: ```javascript const withTimeout = (promise, ms) => Promise.race([ promise, new Promise((_, reject) => setTimeout(() => reject('Timeout'), ms)) ]); ``` If all inputs stay pending forever, `Promise.race()` stays pending forever too. **Promise.any()** Returns the first promise to fulfill. Skips rejections entirely. If all promises reject, it throws an `AggregateError`. Added in ES2021, so check if you need a polyfill for older targets. ```javascript // Use whichever CDN responds first const resource = await Promise.any([ fetch('https://cdn1.example.com/lib.js'), fetch('https://cdn2.example.com/lib.js'), fetch('https://cdn3.example.com/lib.js') ]); ``` ### How it works internally When `resolve()` or `reject()` fires, the Promise marks itself settled and puts the `.then()` or `.catch()` handlers into the microtask queue. Microtasks run after the current synchronous code finishes but before the browser renders or the next `setTimeout` fires. That is why `Promise.resolve().then(fn)` always executes before `setTimeout(fn, 0)`: different queues, different priority. ### Common mistakes **1. Forgetting `return` inside `.then()` with curly braces** ```javascript // Wrong - result is lost, next .then() gets undefined fetch('/api/data') .then(response => { response.json(); // no return }) .then(data => console.log(data)); // undefined // Right fetch('/api/data') .then(response => response.json()) .then(data => console.log(data)); ``` Arrow functions with `{}` do not return implicitly. **2. No `.catch()` at the end of the chain** ```javascript // Wrong - errors disappear, app continues in a broken state fetch('/api').then(r => r.json()).then(showData); // Right fetch('/api').then(r => r.json()).then(showData).catch(console.error); ``` **3. Expecting `Promise.all()` to wait for everything before rejecting** In practice, this is the mistake I see most often in code review. `Promise.all()` bails on the first rejection. It does not wait for slower promises. ```javascript Promise.all([ Promise.resolve('OK'), Promise.reject('BOOM'), // rejects immediately slowPromise // its result is ignored ]).catch(err => console.log(err)); // "BOOM" instantly ``` Use `Promise.allSettled()` when you need every result. **4. Wrapping code that already returns a Promise** ```javascript // Wrong - pointless overhead function loadUser() { return new Promise(resolve => resolve(fetch('/api/user'))); } // Right - fetch already returns a Promise function loadUser() { return fetch('/api/user'); } ``` ### Real-world usage - React `useEffect`: `fetch('/api/data').then(r => r.json()).then(setData).catch(setError)` - Express middleware: `Promise.all([db.query(...), cache.get(...)])` for parallel data fetching - Redux Toolkit: `createAsyncThunk` handles the Promise lifecycle internally - Next.js `getServerSideProps`: `Promise.all([fetchUser(), fetchPosts()])` for parallel SSR fetching ### Follow-up questions **Q:** What is the difference between `Promise.all()` and `Promise.allSettled()`? **A:** `Promise.all()` rejects as soon as one input promise rejects. `Promise.allSettled()` waits for all promises to finish and returns a result object for each, containing `status` and either `value` or `reason`. No early exit. **Q:** Why does `Promise.resolve().then(fn)` run before `setTimeout(fn, 0)`? **A:** `.then()` callbacks go to the microtask queue. `setTimeout` goes to the macrotask queue. After each task, the engine drains all pending microtasks before picking the next macrotask. Microtasks always go first. **Q:** What happens when you pass an empty array to `Promise.all([])`? **A:** It resolves immediately with `[]`. No promises to wait for. **Q:** Can a Promise resolve with another Promise as its value? **A:** Yes. If you call `resolve(anotherPromise)`, the outer Promise adopts the state of the inner one and waits for it to settle. Any object with a `.then()` method (a "thenable") gets treated the same way. **Q:** What does `Promise.race()` return if all inputs stay pending forever? **A:** It stays pending forever. Nothing resolves or rejects it. ## Examples ### Loading user data with error handling ```javascript function loadUserProfile(userId) { return fetch(`/api/users/${userId}`) .then(response => { if (!response.ok) throw new Error('User not found'); return response.json(); }) .catch(error => { console.error('Profile load failed:', error.message); return null; // graceful fallback }); } loadUserProfile(1).then(profile => { if (profile) renderProfile(profile); }); ``` Throwing inside `.then()` is identical to calling `reject()`. The error goes straight to the nearest `.catch()`. ### Parallel dashboard requests ```javascript async function loadDashboard(userId) { try { const [user, posts, notifications] = await Promise.all([ fetch(`/api/users/${userId}`).then(r => r.json()), fetch(`/api/posts?author=${userId}`).then(r => r.json()), fetch(`/api/notifications/${userId}`).then(r => r.json()) ]); return { user, posts, notifications }; } catch (error) { console.error('Dashboard failed:', error); return null; } } ``` Three requests fire at once. Total time equals the slowest one, not the sum of all three. ### The Promise.all rejection edge case ```javascript const tasks = [ Promise.resolve('Fast'), new Promise(resolve => setTimeout(() => resolve('Slow'), 100)), Promise.reject('BOOM!'), // rejects immediately new Promise(resolve => setTimeout(() => resolve('Never used'), 200)) ]; Promise.all(tasks) .then(results => console.log(results)) .catch(err => console.log('Failed:', err)); // "Failed: BOOM!" - no delay ``` The 200ms promise never delivers. `Promise.all()` already rejected. Switch to `Promise.allSettled()` and filter by `status` if you need all results.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.