[{"data":1,"prerenderedAt":178},["ShallowReactive",2],{"qa-\u002Fjavascript\u002Fasync\u002Fpromises":3},{"page":4,"siblings":170,"blog":175},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":20,"path":21,"questions":22,"related":161,"seo":162,"seoDescription":163,"stem":164,"subtopic":165,"topic":166,"topicSlug":167,"updated":168,"__hash__":169},"qa\u002Fjavascript\u002Fasync\u002Fpromises.md","Promises",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md","JavaScript","javascript",{},true,1,"\u002Fjavascript\u002Fasync\u002Fpromises",[23,28,32,36,40,44,49,53,57,61,65,69,73,77,81,85,89,93,97,101,105,109,113,117,121,125,129,133,137,141,145,149,153,157],{"id":24,"difficulty":25,"q":26,"a":27},"what-is-promise","easy","What is a Promise?","A Promise is an object representing the **eventual** result of an asynchronous\noperation — a placeholder for a value you don't have yet. It lives in one of\nthree states:\n\n- `pending` — the starting state, not yet settled.\n- `fulfilled` — completed successfully, carries a value.\n- `rejected` — failed, carries a reason (usually an `Error`).\n\n```js\nconst p = new Promise((resolve, reject) => {\n  setTimeout(() => resolve('done'), 100) \u002F\u002F settles after 100ms\n})\np.then(value => console.log(value)) \u002F\u002F 'done'\n```\n\nTwo properties make promises predictable: they're **settled once** (a\npending promise transitions to fulfilled *or* rejected exactly one time and\nthen its state\u002Fvalue are **immutable**), and `.then`\u002F`.catch` always run\n**asynchronously** as microtasks — never synchronously, even for an\nalready-resolved promise.\n",{"id":29,"difficulty":14,"q":30,"a":31},"async-await","What is async\u002Fawait and how does it relate to promises?","`async`\u002F`await` is **syntactic sugar over promises** — it doesn't add new\ncapabilities, it makes promise code read like ordinary sequential code. Two\nrules: an `async` function **always returns a promise** (any value you return\nis wrapped in a resolved promise; any throw becomes a rejected one), and\n`await` **pauses** the function until the awaited promise settles, then\nresumes with its value.\n\n```js\nasync function load() {\n  const res = await fetch('\u002Fapi')   \u002F\u002F pause until the request resolves\n  return res.json()                 \u002F\u002F also awaited by the caller\n}\nload().then(data => console.log(data)) \u002F\u002F still a promise underneath\n```\n\nCrucially, `await` only suspends the *current async function* — the rest of\nthe program keeps running. Under the hood the code after an `await` becomes a\n`.then` continuation scheduled as a microtask.\n",{"id":33,"difficulty":14,"q":34,"a":35},"error-handling","How do you handle errors with promises and async\u002Fawait?","With raw promises, attach `.catch()` to handle a rejection anywhere up the\nchain. With `async`\u002F`await`, an awaited rejected promise **throws**, so you use\na normal `try\u002Fcatch`.\n\n```js\n\u002F\u002F promise style\nload().then(use).catch(err => console.error(err))\n\n\u002F\u002F async\u002Fawait style — reads like synchronous try\u002Fcatch\ntry {\n  const data = await load()\n  use(data)\n} catch (err) {\n  console.error(err)\n} finally {\n  hideSpinner() \u002F\u002F runs whether it succeeded or failed\n}\n```\n\nGotchas interviewers probe: a single `.catch()` at the end catches errors from\n*every* prior step in the chain; an **unhandled** rejection triggers an\n`unhandledrejection` event\u002Fwarning; and forgetting to `await` (or `return`) a\npromise inside a `try` means its rejection escapes the `catch` entirely.\n",{"id":37,"difficulty":14,"q":38,"a":39},"promise-all","What is the difference between Promise.all and Promise.allSettled?","Both take an iterable of promises and run them concurrently, but they differ in\nhow they handle failure:\n\n- `Promise.all` **short-circuits**: it fulfills with an array of all values\n  once **every** promise fulfills, but rejects **immediately** the moment\n  **any one** rejects — you lose the results of the others.\n- `Promise.allSettled` **never rejects**: it waits for **every** promise to\n  settle and resolves with an array of `{ status, value }` or\n  `{ status, reason }` objects, so you can inspect each outcome.\n\n```js\nconst results = await Promise.allSettled([fetchA(), fetchB(), fetchC()])\nresults.forEach(r => {\n  if (r.status === 'fulfilled') console.log('ok', r.value)\n  else console.log('failed', r.reason)\n})\n```\n\nReach for `all` when you need *all-or-nothing* (one failure should abort);\nreach for `allSettled` when you want every result regardless of partial\nfailures (e.g. a dashboard of independent widgets).\n",{"id":41,"difficulty":14,"q":42,"a":43},"promise-race","What do Promise.race and Promise.any do?","Both settle based on the **first** promise to finish, but they disagree on what\ncounts:\n\n- `Promise.race` settles as soon as the first promise **settles** — whether it\n  fulfills *or* rejects. The first one to cross the line wins, error or not.\n- `Promise.any` resolves with the first promise to **fulfill**, ignoring\n  rejections. It only rejects if **all** of them reject, with an\n  `AggregateError` bundling every reason.\n\n```js\n\u002F\u002F timeout pattern — race the work against a timer\nconst data = await Promise.race([\n  fetch('\u002Fapi'),\n  new Promise((_, rej) => setTimeout(() => rej(new Error('timeout')), 5000)),\n])\n\n\u002F\u002F first successful mirror wins; only fails if every mirror is down\nconst fastest = await Promise.any([fetch(mirror1), fetch(mirror2)])\n```\n\nMnemonic: **race** cares about *first to finish*, **any** cares about *first to\nsucceed*.\n",{"id":45,"difficulty":46,"q":47,"a":48},"sequential-parallel","hard","How do you run async tasks in parallel vs sequentially?","The difference is **when you start** each task. `await` inside a loop starts\nthe next task only after the previous one resolves — that's **sequential** and\noften an accidental performance bug. To go **parallel**, kick them all off\nfirst (so they run concurrently), then `await` them together.\n\n```js\n\u002F\u002F sequential: ~A + B + C total time\nfor (const url of urls) {\n  results.push(await fetch(url))\n}\n\n\u002F\u002F parallel: ~max(A, B, C) total time\nconst results = await Promise.all(urls.map(url => fetch(url)))\n```\n\nUse sequential intentionally when each step **depends on the previous one's\nresult** or you must avoid hammering a rate-limited API. Use parallel when the\ntasks are independent — it can be dramatically faster.\n",{"id":50,"difficulty":46,"q":51,"a":52},"microtask","Why does an awaited promise callback run before a setTimeout?","Because promise continuations are scheduled as **microtasks**, while\n`setTimeout` callbacks are **macrotasks** — and the event loop drains the\n*entire* microtask queue after the current synchronous code, *before* it ever\nreaches the next macrotask.\n\n```js\nconsole.log(1)\nsetTimeout(() => console.log(2), 0)        \u002F\u002F macrotask\nPromise.resolve().then(() => console.log(3)) \u002F\u002F microtask\nconsole.log(4)\n\u002F\u002F Output: 1, 4, 3, 2 — the promise (3) beats the timer (2)\n```\n\nSo even `setTimeout(fn, 0)` is effectively \"run after all pending microtasks,\"\nwhich is why a resolved promise's `.then` always fires first.\n",{"id":54,"difficulty":14,"q":55,"a":56},"promisify","How do you convert a callback-based API to a promise?","Wrap the callback API in `new Promise(...)` and translate the callback's\noutcome into `resolve`\u002F`reject`. For Node-style `(err, value)` callbacks, the\nconvention is \"error first\": reject on `err`, otherwise resolve with the value.\n\n```js\n\u002F\u002F simple timer\nconst wait = ms => new Promise(resolve => setTimeout(resolve, ms))\n\n\u002F\u002F wrapping a Node-style error-first callback\nconst readFileAsync = path =>\n  new Promise((resolve, reject) => {\n    fs.readFile(path, 'utf8', (err, data) => {\n      if (err) reject(err)\n      else resolve(data)\n    })\n  })\n```\n\nIn Node you'd usually reach for the built-in `util.promisify` instead of\nhand-rolling this, but interviewers like to see you can build it from scratch.\n",{"id":58,"difficulty":14,"q":59,"a":60},"chaining","How does promise chaining work?","Each `.then` returns a **new promise** that resolves with whatever its callback\nreturns, so you can chain steps where each receives the previous result. This\nflattens nested callbacks into a linear sequence.\n\n```js\nfetch('\u002Fapi\u002Fuser')\n  .then(res => res.json())     \u002F\u002F returns parsed body\n  .then(user => fetch(`\u002Fapi\u002Fposts\u002F${user.id}`))\n  .then(res => res.json())\n  .then(posts => console.log(posts))\n  .catch(err => console.error(err))\n```\n\nThe chain runs step by step; returning a value passes it down, returning a\npromise waits for it. A single trailing `.catch` handles errors from any step.\n",{"id":62,"difficulty":14,"q":63,"a":64},"then-return-value","What does .then return and why does it matter?","`.then` always returns a **new promise**. What that promise resolves to depends on\nthe callback: a plain value -> resolves with it; a promise -> **adopts** that\npromise's eventual value (flattening); a `throw` -> rejects.\n\n```js\nPromise.resolve(1)\n  .then(x => x + 1)               \u002F\u002F resolves 2\n  .then(x => Promise.resolve(x*10)) \u002F\u002F resolves 20 (adopted)\n  .then(x => { throw new Error() }) \u002F\u002F rejects\n  .then(x => console.log('skipped'))\n  .catch(() => console.log('caught'))\n```\n\nBecause each `.then` is a fresh promise, chaining and error propagation \"just\nwork\" — and forgetting to **return** inside a `.then` breaks the chain (the next\nstep gets `undefined`).\n",{"id":66,"difficulty":14,"q":67,"a":68},"catch-chain","Where should you place .catch in a chain?","Usually a **single `.catch` at the end** of the chain — it handles a rejection\nfrom **any** preceding step, because errors propagate down until caught. Place an\nintermediate `.catch` only if you want to **recover** and continue the chain.\n\n```js\nstep1().then(step2).then(step3)\n  .catch(err => console.error('any step failed', err))\n\n\u002F\u002F recover mid-chain:\nload().catch(() => fallback()).then(use) \u002F\u002F continues with fallback's value\n```\n\nA `.catch` that returns a value produces a **resolved** promise, so the chain\ncontinues normally after recovery.\n",{"id":70,"difficulty":25,"q":71,"a":72},"finally-block","What does .finally do?","`.finally(cb)` runs `cb` **whether the promise fulfilled or rejected** — for\ncleanup that should always happen (hide a spinner, close a connection). It\nreceives **no argument** and, importantly, **passes the original value\u002Ferror\nthrough** unchanged.\n\n```js\nshowSpinner()\nfetchData()\n  .then(use)\n  .catch(handle)\n  .finally(() => hideSpinner()) \u002F\u002F always runs, doesn't alter the result\n```\n\nCaveat: if `.finally`'s callback itself throws or returns a rejected promise, it\n*does* override the outcome — but a normal return is ignored.\n",{"id":74,"difficulty":46,"q":75,"a":76},"unhandled-rejection","What is an unhandled promise rejection?","A rejected promise with **no `.catch`** (or no `try\u002Fcatch` around its `await`) is\n\"unhandled.\" Browsers fire an `unhandledrejection` event and log a warning; Node\nprints a warning and (in recent versions) **crashes the process** by default.\n\n```js\nPromise.reject(new Error('boom')) \u002F\u002F no handler -> unhandled rejection\n\nwindow.addEventListener('unhandledrejection', e => {\n  console.error('unhandled:', e.reason)\n  e.preventDefault()\n})\n```\n\nAlways attach a `.catch` or wrap awaits in `try\u002Fcatch`. A global handler is a\nsafety net for logging, not a substitute for handling errors at the source.\n",{"id":78,"difficulty":25,"q":79,"a":80},"resolve-reject-static","What do Promise.resolve and Promise.reject do?","They create **already-settled** promises: `Promise.resolve(v)` returns a promise\nfulfilled with `v` (or adopts `v` if it's already a promise\u002Fthenable), and\n`Promise.reject(e)` returns one rejected with `e`. Handy for returning a\nconsistent promise type or starting a chain.\n\n```js\nfunction getUser(id) {\n  const cached = cache.get(id)\n  if (cached) return Promise.resolve(cached) \u002F\u002F sync value as a promise\n  return fetch(`\u002Fapi\u002F${id}`).then(r => r.json())\n}\n```\n\n`Promise.resolve` is also how `await` wraps non-promise values, and how you\nnormalize \"maybe a value, maybe a promise\" into always-a-promise.\n",{"id":82,"difficulty":46,"q":83,"a":84},"thenable","What is a thenable?","A thenable is **any object with a `.then(resolve, reject)` method**. The promise\nmachinery treats thenables like promises — `await` and `Promise.resolve` will\n\"follow\" a thenable by calling its `then`. This is what makes different promise\nlibraries interoperate.\n\n```js\nconst thenable = {\n  then(resolve) { resolve(42) }\n}\nPromise.resolve(thenable).then(v => console.log(v)) \u002F\u002F 42\nawait thenable                                       \u002F\u002F 42\n```\n\nIt's why returning a thenable from `.then` flattens it. The downside: any object\nthat *happens* to have a `then` method gets treated specially — a rare source of\nsurprises.\n",{"id":86,"difficulty":14,"q":87,"a":88},"throw-in-then","What happens if you throw inside a .then callback?","Throwing inside a `.then` (or `.catch`) callback **rejects** the promise that\n`.then` returns, so the error skips subsequent `.then`s and is caught by the next\n`.catch` down the chain.\n\n```js\nPromise.resolve()\n  .then(() => { throw new Error('fail') })\n  .then(() => console.log('skipped'))      \u002F\u002F not run\n  .catch(err => console.log('caught:', err.message)) \u002F\u002F caught: fail\n```\n\nThis is what makes promise error handling feel like synchronous `try\u002Fcatch` — a\nthrown error propagates to the nearest handler instead of crashing.\n",{"id":90,"difficulty":14,"q":91,"a":92},"return-promise-then","What happens when you return a promise from .then?","The outer chain **waits** for that returned promise to settle and adopts its\nresult — this is \"flattening.\" It's how you sequence async steps without nesting.\n\n```js\ngetUser()\n  .then(user => fetchPosts(user.id)) \u002F\u002F returns a promise\n  .then(posts => console.log(posts)) \u002F\u002F runs only after fetchPosts resolves\n```\n\nPromises never nest as `Promise\u003CPromise\u003CT>>`; returning a promise from `.then`\nauto-unwraps it. Forgetting to **return** it, though, means the next step runs\nimmediately with `undefined`.\n",{"id":94,"difficulty":14,"q":95,"a":96},"nested-vs-flat","How do you flatten nested .then callbacks?","Nesting `.then`s recreates callback hell. Because returning a promise flattens the\nchain, you can keep it **flat** by returning instead of nesting.\n\n```js\n\u002F\u002F nested (\"promise hell\")\na().then(x => {\n  b(x).then(y => {\n    c(y).then(z => console.log(z))\n  })\n})\n\u002F\u002F flat\na().then(b).then(c).then(z => console.log(z))\n```\n\n`async\u002Fawait` flattens it even more readably. Nesting is occasionally needed when\nan inner step requires an **outer** value, but usually a flat chain (or await)\navoids it.\n",{"id":98,"difficulty":46,"q":99,"a":100},"reduce-sequential","How do you run promises sequentially using reduce?","Chain them by reducing over an array, where each step awaits the accumulator\npromise before starting — guaranteeing order and one-at-a-time execution.\n\n```js\nconst urls = ['\u002Fa', '\u002Fb', '\u002Fc']\nawait urls.reduce(\n  (chain, url) => chain.then(() => fetch(url)),\n  Promise.resolve()\n)\n\u002F\u002F or with await in a for...of:\nfor (const url of urls) await fetch(url)\n```\n\nUse this when each request must finish before the next (ordering, rate limits,\ndependencies). For independent requests, `Promise.all` is faster.\n",{"id":102,"difficulty":46,"q":103,"a":104},"concurrency-limit","How do you limit the concurrency of many async tasks?","Running thousands of requests at once with `Promise.all` can overwhelm a server\nor hit rate limits. Cap the number in flight with a **worker pool**: N workers\npulling from a shared queue.\n\n```js\nasync function pool(items, limit, fn) {\n  const results = []\n  const queue = [...items.entries()]\n  async function worker() {\n    for (const [i, item] of queue.splice(0)) results[i] = await fn(item)\n  }\n  await Promise.all(Array.from({ length: limit }, worker))\n  return results\n}\nawait pool(urls, 5, fetch) \u002F\u002F at most 5 concurrent requests\n```\n\nLibraries like `p-limit` provide this off the shelf. The idea: parallelism, but\n**bounded**.\n",{"id":106,"difficulty":46,"q":107,"a":108},"retry-backoff","How do you implement retry with exponential backoff?","Wrap the operation in a loop that catches failures and waits an increasing delay\nbefore retrying, up to a max attempt count.\n\n```js\nasync function retry(fn, attempts = 3, delay = 200) {\n  for (let i = 0; i \u003C attempts; i++) {\n    try {\n      return await fn()\n    } catch (err) {\n      if (i === attempts - 1) throw err\n      await new Promise(r => setTimeout(r, delay * 2 ** i)) \u002F\u002F 200, 400, 800...\n    }\n  }\n}\n```\n\nExponential backoff (often with jitter) avoids hammering a struggling service.\nOnly retry **idempotent**\u002Ftransient failures — retrying a non-idempotent write\ncan duplicate effects.\n",{"id":110,"difficulty":14,"q":111,"a":112},"for-await-of","What is for await...of and when do you use it?","`for await...of` iterates an **async iterable** (or an iterable of promises),\nawaiting each value in turn — ideal for consuming streams or paginated APIs\nsequentially.\n\n```js\nfor await (const chunk of readableStream) {\n  process(chunk) \u002F\u002F each chunk awaited in order\n}\n\nfor await (const value of [fetch('\u002Fa'), fetch('\u002Fb')]) {\n  console.log(value) \u002F\u002F awaits each promise sequentially\n}\n```\n\nIt processes items **one at a time** (sequential). For concurrent processing of\na fixed array, `Promise.all(arr.map(...))` is the right tool instead.\n",{"id":114,"difficulty":14,"q":115,"a":116},"top-level-await","What is top-level await?","In **ES modules**, you can use `await` at the **top level**, outside any async\nfunction. The module's evaluation pauses until the awaited promise settles, and\nimporters wait for it.\n\n```js\n\u002F\u002F config.mjs\nconst res = await fetch('\u002Fconfig.json')\nexport const config = await res.json()\n```\n\nIt's great for module initialization (loading config, dynamic imports,\nconnecting). Caveat: it can **delay** the loading of dependent modules, so avoid\nslow top-level awaits in widely-imported modules. Not available in CommonScript\nscripts.\n",{"id":118,"difficulty":46,"q":119,"a":120},"cancellation","How do you cancel a promise or async operation?","Promises themselves **can't be cancelled** — once started they run to settlement.\nThe standard approach is an **`AbortController`**: pass its `signal` to\ncancellable APIs (`fetch`, timers) and call `abort()` to stop them.\n\n```js\nconst ctrl = new AbortController()\nfetch('\u002Fslow', { signal: ctrl.signal })\n  .catch(e => { if (e.name === 'AbortError') console.log('cancelled') })\nctrl.abort() \u002F\u002F triggers an AbortError rejection\n```\n\nFor your own async functions, check `signal.aborted` at await points and bail\nout. The promise still settles (as a rejection); \"cancellation\" means stopping\nthe underlying work and ignoring the result.\n",{"id":122,"difficulty":46,"q":123,"a":124},"await-in-foreach","Why doesn't await work inside forEach?","`Array.prototype.forEach` **ignores** the return value of its callback, so it\ndoesn't await the async callback's promise — the loop fires all callbacks and\nmoves on immediately, not waiting for any of them.\n\n```js\n\u002F\u002F does NOT wait; \"done\" logs before any item is processed\nitems.forEach(async item => { await process(item) })\nconsole.log('done')\n\n\u002F\u002F sequential\nfor (const item of items) await process(item)\n\u002F\u002F concurrent\nawait Promise.all(items.map(item => process(item)))\n```\n\nUse `for...of` (sequential) or `map` + `Promise.all` (concurrent). `forEach` is\nsimply not async-aware.\n",{"id":126,"difficulty":46,"q":127,"a":128},"await-parallel-start","How do you start async tasks in parallel but await them later?","Call the async functions **first** (which starts them immediately) and store the\npromises, then `await` them afterward. The work overlaps because it began before\nany `await`.\n\n```js\nconst pa = fetchA() \u002F\u002F starts now\nconst pb = fetchB() \u002F\u002F starts now (concurrently)\nconst a = await pa  \u002F\u002F wait for both, but they already ran in parallel\nconst b = await pb\n```\n\nContrast with `const a = await fetchA(); const b = await fetchB()` which is\nsequential. `Promise.all([pa, pb])` is the cleaner equivalent and also propagates\nerrors as soon as one fails.\n",{"id":130,"difficulty":14,"q":131,"a":132},"parallel-map-all","How do you process an array concurrently with Promise.all and map?","Map each element to a promise (starting all the work), then `Promise.all` to wait\nfor the whole batch and collect results **in order**.\n\n```js\nconst results = await Promise.all(\n  ids.map(id => fetchUser(id))\n)\n\u002F\u002F results[i] corresponds to ids[i], even if they resolved out of order\n```\n\nThis runs everything concurrently — far faster than awaiting in a loop. Beware\nunbounded concurrency for large arrays (use a concurrency limit), and remember\n`Promise.all` rejects as soon as **any** task fails.\n",{"id":134,"difficulty":14,"q":135,"a":136},"explicit-construction-antipattern","What is the explicit promise construction antipattern?","Wrapping an **already-promise-returning** operation in `new Promise` is redundant,\nverbose, and easy to get wrong (forgetting to reject, swallowing errors). Just\nreturn\u002Fawait the existing promise.\n\n```js\n\u002F\u002F antipattern — wrapping a promise in a promise\nfunction load() {\n  return new Promise((resolve, reject) => {\n    fetch('\u002Fx').then(resolve).catch(reject)\n  })\n}\n\u002F\u002F just return it\nfunction load() { return fetch('\u002Fx') }\n```\n\nUse `new Promise` **only** to wrap a **callback-based** API that isn't already\npromisified.\n",{"id":138,"difficulty":14,"q":139,"a":140},"async-vs-then-style","When should you use async\u002Fawait vs .then chains?","They're interchangeable, but `async\u002Fawait` usually reads better, especially with\nbranching, loops, and try\u002Fcatch error handling. `.then` chains shine for simple\nlinear transformations and point-free style.\n\n```js\n\u002F\u002F await: clearer with logic between steps\nasync function load() {\n  const user = await getUser()\n  if (!user.active) return null\n  return getPosts(user.id)\n}\n\u002F\u002F then: fine for a straight pipeline\nconst upper = () => fetch('\u002Fx').then(r => r.text()).then(t => t.toUpperCase())\n```\n\nMixing is fine. Prefer `await` for readability; just remember every `await`\nintroduces a microtask boundary.\n",{"id":142,"difficulty":25,"q":143,"a":144},"promise-immutable","Can a promise change its state after settling?","No. A promise transitions **once** from `pending` to either `fulfilled` or\n`rejected`, and after that its state and value are **immutable**. Calling\n`resolve`\u002F`reject` again does nothing.\n\n```js\nconst p = new Promise((resolve, reject) => {\n  resolve('first')\n  resolve('second') \u002F\u002F ignored\n  reject('error')   \u002F\u002F ignored\n})\np.then(v => console.log(v)) \u002F\u002F 'first'\n```\n\nThis guarantee is what makes promises composable: once you have a settled\npromise, its result never changes, and adding more `.then`s later still gives you\nthat same value.\n",{"id":146,"difficulty":14,"q":147,"a":148},"promise-all-empty","What does Promise.all([]) resolve to?","`Promise.all([])` resolves **immediately** with an **empty array** — there's\nnothing to wait for. The same edge case applies to `allSettled([])` (empty\narray). But `Promise.any([])` **rejects** with an `AggregateError` (nothing can\nfulfill), and `Promise.race([])` stays **pending forever**.\n\n```js\nawait Promise.all([])      \u002F\u002F []\nawait Promise.allSettled([]) \u002F\u002F []\nawait Promise.race([])     \u002F\u002F never settles\n```\n\nThese empty-array behaviors are classic gotchas — guard against an empty input\nlist if it could occur, especially for `race`\u002F`any`.\n",{"id":150,"difficulty":14,"q":151,"a":152},"partial-failures","How do you handle partial failures across multiple async tasks?","Use **`Promise.allSettled`**, which waits for every task and reports each\noutcome, so one failure doesn't discard the successes (as `Promise.all` would).\n\n```js\nconst results = await Promise.allSettled(urls.map(fetch))\nconst ok = results.filter(r => r.status === 'fulfilled').map(r => r.value)\nconst failed = results.filter(r => r.status === 'rejected').map(r => r.reason)\n```\n\nThis is the right tool for dashboards, batch jobs, and \"best-effort\" operations\nwhere you want all results regardless of individual failures.\n",{"id":154,"difficulty":14,"q":155,"a":156},"fire-and-forget","What are the risks of \"fire and forget\" promises?","Calling an async function without awaiting or attaching `.catch` (\"floating\npromise\") means errors become **unhandled rejections**, and you lose control over\nordering and completion.\n\n```js\n\u002F\u002F floating — errors vanish, no way to know when it's done\nsaveAnalytics(data)\n\n\u002F\u002F at least handle errors\nsaveAnalytics(data).catch(err => log(err))\n\u002F\u002F or await if the result\u002Fordering matters\nawait saveAnalytics(data)\n```\n\nIf you intentionally don't await, **always** attach a `.catch`. Linters\n(`no-floating-promises`) flag these because silent failures are hard to debug.\n",{"id":158,"difficulty":14,"q":159,"a":160},"await-error-multiple","How do you handle errors across multiple awaits?","A single `try\u002Fcatch` around the awaits catches a rejection from **any** of them —\nexecution jumps to `catch` at the first failure, skipping the rest.\n\n```js\ntry {\n  const user = await getUser()\n  const posts = await getPosts(user.id)\n  const stats = await getStats(posts)\n} catch (err) {\n  \u002F\u002F catches whichever await rejected first\n  console.error(err)\n}\n```\n\nFor **independent** operations where you want all errors (not just the first),\nuse `Promise.allSettled` and inspect each result instead of letting the first\nrejection short-circuit.\n",null,{"description":11},"JavaScript promise and async\u002Fawait interview questions — states, chaining, error handling, Promise.all vs race, and converting callbacks.","javascript\u002Fasync\u002Fpromises","Promises & async\u002Fawait","Asynchronous JavaScript","async","2026-06-17","qvoFc9byIt-vpMOLYR4_aXHuFSUm0hmc9QGBW5Vegyw",[171,172],{"subtopic":165,"path":21,"order":20},{"subtopic":173,"path":174,"order":12},"The Event Loop","\u002Fjavascript\u002Fasync\u002Fevent-loop",{"path":176,"title":177},"\u002Fblog\u002Fjavascript-promises-async-await","JavaScript Promises & Async\u002FAwait — The Complete Guide",1781808675825]