[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"verticals":3,"playground-promise-concurrency-all-settled-any-race":32},[4,20],{"id":5,"slug":6,"name":7,"tagline":8,"description":9,"accentFrom":10,"accentTo":11,"icon":12,"defaultLocale":13,"locales":14,"features":16,"position":19},"019fe637-3d33-714b-b57f-23e163ffca0c","dev","Web Development","Build. Learn. Ship.","Practical courses, engineering-grade articles and open-source tools for people who ship.","violet-500","cyan-400","◇","en",[13,15],"fa",{"courses":17,"paths":17,"articles":17,"exams":18,"flashcards":18,"packages":17,"community":17,"certificates":17,"teams":17,"commerce":17},true,false,0,{"id":21,"slug":22,"name":23,"tagline":24,"description":25,"accentFrom":26,"accentTo":10,"icon":27,"defaultLocale":13,"locales":28,"features":30,"position":31},"019fe637-3dc2-754c-8657-0f175bfee7c6","lang","Languages","Learn a language the way you learn a codebase.","Structured paths, listening drills and spaced repetition that actually sticks.","amber-400","⌘",[13,15,29],"es",{"courses":17,"paths":17,"articles":18,"exams":18,"flashcards":18,"packages":18,"community":17,"certificates":18,"teams":18,"commerce":17},2,{"slug":33,"title":34,"summary":35,"html":36,"css":37,"js":38,"config":39,"doc":41},"promise-concurrency-all-settled-any-race","Promise.all vs allSettled vs any vs race — a live lab",null,"\u003Cdiv class=\"wrap\">\n    \u003Ch1>🎮 Promise concurrency lab\u003C\u002Fh1>\n    \u003Cp class=\"sub\">\n      Same four requests, fired at once. Set each one's \u003Cstrong>latency\u003C\u002Fstrong> and whether it\n      \u003Cstrong>fails\u003C\u002Fstrong>, pick a combinator, and hit \u003Cstrong>Run\u003C\u002Fstrong> — watch the exact moment the\n      group settles, and what it \u003Cem>keeps\u003C\u002Fem> vs. \u003Cem>throws away\u003C\u002Fem>.\n    \u003C\u002Fp>\n\n    \u003C!-- 1 · METHOD PICKER (kept above the fold in the embed) -->\n    \u003Cdiv class=\"panel\">\n      \u003Ch2>1 · Pick a combinator\u003C\u002Fh2>\n      \u003Cdiv class=\"seg\" role=\"group\" aria-label=\"Promise combinator\">\n        \u003Cbutton data-method=\"all\"        aria-pressed=\"true\">Promise.all\u003C\u002Fbutton>\n        \u003Cbutton data-method=\"allSettled\" aria-pressed=\"false\">Promise.allSettled\u003C\u002Fbutton>\n        \u003Cbutton data-method=\"any\"        aria-pressed=\"false\">Promise.any\u003C\u002Fbutton>\n        \u003Cbutton data-method=\"race\"       aria-pressed=\"false\">Promise.race\u003C\u002Fbutton>\n      \u003C\u002Fdiv>\n      \u003Cp class=\"method-desc\" id=\"methodDesc\">\u003C\u002Fp>\n    \u003C\u002Fdiv>\n\n    \u003C!-- RUN BAR -->\n    \u003Cdiv class=\"runbar\">\n      \u003Cbutton id=\"run\">▶ Run\u003C\u002Fbutton>\n      \u003Cbutton id=\"reset\" class=\"ghost\">Reset\u003C\u002Fbutton>\n      \u003Cspan class=\"grow\">\u003C\u002Fspan>\n      \u003Cspan class=\"clock\" id=\"clock\">0 ms\u003C\u002Fspan>\n    \u003C\u002Fdiv>\n\n    \u003C!-- 2 · THE REQUESTS -->\n    \u003Cdiv class=\"panel\">\n      \u003Ch2>2 · The four requests\u003C\u002Fh2>\n      \u003Cdiv id=\"rows\">\u003C\u002Fdiv>\n      \u003Cdiv class=\"presets\">\n        \u003Cspan class=\"lbl\">Presets\u003C\u002Fspan>\n        \u003Cbutton data-preset=\"succeed\">All succeed\u003C\u002Fbutton>\n        \u003Cbutton data-preset=\"alerts\">Alerts fails (500)\u003C\u002Fbutton>\n        \u003Cbutton data-preset=\"slow\">One is slow\u003C\u002Fbutton>\n        \u003Cbutton data-preset=\"allfail\">All fail\u003C\u002Fbutton>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"legend\" aria-hidden=\"true\">\n        \u003Cspan>\u003Ci class=\"sw\" style=\"background:var(--good)\">\u003C\u002Fi> resolved\u003C\u002Fspan>\n        \u003Cspan>\u003Ci class=\"sw\" style=\"background:var(--bad)\">\u003C\u002Fi> rejected\u003C\u002Fspan>\n        \u003Cspan>\u003Ci class=\"sw\" style=\"background:var(--accent)\">\u003C\u002Fi> decided the group\u003C\u002Fspan>\n        \u003Cspan>\u003Ci class=\"sw\" style=\"background:var(--muted)\">\u003C\u002Fi> discarded \u002F ignored\u003C\u002Fspan>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003C!-- 3 · OUTPUT -->\n    \u003Cdiv class=\"panel\">\n      \u003Ch2>3 · What the group returned\u003C\u002Fh2>\n      \u003Cp class=\"status\" id=\"status\">\u003Cspan class=\"dot\">•\u003C\u002Fspan>\u003Cspan class=\"idle\" id=\"statusText\">Press \u003Cstrong>Run\u003C\u002Fstrong> to fire all four requests concurrently.\u003C\u002Fspan>\u003C\u002Fp>\n      \u003Cpre>\u003Ccode id=\"output\" class=\"c\">\u002F\u002F the resolved value(s) or the rejection will appear here\u003C\u002Fcode>\u003C\u002Fpre>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>",":root {\n    --bg: #0d1117; --panel: #161b22; --ink: #e8ebf2; --muted: #9aa4b2;\n    --accent: #7c9cff; --good: #3fb950; --bad: #f0883e; --line: #232a35;\n    --rail: #0b0e14;\n    font-family: ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif;\n  }\n  * { box-sizing: border-box; }\n  body { margin: 0; background: var(--bg); color: var(--ink); min-height: 100vh;\n    display: flex; align-items: flex-start; justify-content: center; padding: 18px; }\n  .wrap { width: 100%; max-width: 720px; }\n\n  h1 { font-size: 1.2rem; margin: 0 0 3px; letter-spacing: -0.01em; }\n  .sub { color: var(--muted); font-size: .9rem; margin: 0 0 14px; line-height: 1.45; }\n  .sub code { color: var(--accent); background: #ffffff10; padding: 1px 5px; border-radius: 5px; }\n\n  .panel { background: var(--panel); border: 1px solid var(--line);\n    border-radius: 14px; padding: 16px; margin-bottom: 14px; }\n  .panel h2 { font-size: .72rem; text-transform: uppercase; letter-spacing: .07em;\n    color: var(--muted); margin: 0 0 12px; font-weight: 700; }\n\n  \u002F* buttons *\u002F\n  button { font: inherit; font-weight: 600; color: #0b0d10; background: var(--accent);\n    border: 0; border-radius: 10px; padding: 9px 16px; cursor: pointer; }\n  button.ghost { background: transparent; color: var(--ink); border: 1px solid var(--line); }\n  button.ghost:hover { border-color: var(--accent); }\n  button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }\n  button:disabled { opacity: .45; cursor: not-allowed; }\n\n  \u002F* segmented method picker *\u002F\n  .seg { display: flex; flex-wrap: wrap; gap: 6px; background: var(--rail);\n    border: 1px solid var(--line); border-radius: 12px; padding: 5px; }\n  .seg button { flex: 1 1 auto; background: transparent; color: var(--muted);\n    border-radius: 8px; padding: 8px 10px; font-size: .84rem; white-space: nowrap; }\n  .seg button[aria-pressed=\"true\"] { background: var(--accent); color: #0b0d10; }\n  .seg button:not([aria-pressed=\"true\"]):hover { color: var(--ink); }\n  .method-desc { color: var(--ink); font-size: .86rem; line-height: 1.5; margin: 11px 2px 0;\n    min-height: 2.4em; }\n  .method-desc code { color: var(--accent); }\n\n  \u002F* run bar *\u002F\n  .runbar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 14px; }\n  .runbar .grow { flex: 1 1 auto; }\n  .runbar .clock { font-variant-numeric: tabular-nums; color: var(--muted); font-size: .82rem;\n    min-width: 62px; text-align: right; }\n  .presets { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }\n  .presets .lbl { color: var(--muted); font-size: .74rem; text-transform: uppercase;\n    letter-spacing: .06em; align-self: center; margin-right: 2px; }\n  .presets button { background: transparent; color: var(--ink); border: 1px solid var(--line);\n    border-radius: 999px; padding: 6px 12px; font-size: .8rem; font-weight: 500; }\n  .presets button:hover { border-color: var(--accent); }\n\n  \u002F* request rows *\u002F\n  .req { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px;\n    padding: 12px 0; border-top: 1px solid var(--line); }\n  .req:first-of-type { border-top: 0; padding-top: 2px; }\n  .req.dim { opacity: .5; }\n\n  .name-cell { width: 132px; flex: 0 0 auto; }\n  .name-cell .nm { font-weight: 700; font-size: .92rem; }\n  .tag { display: inline-block; margin-top: 4px; font-size: .68rem; font-weight: 700;\n    letter-spacing: .02em; padding: 2px 8px; border-radius: 999px; }\n  .tag[hidden] { display: none; }\n  .tag.used   { color: var(--good); background: #3fb9501a; }\n  .tag.discard{ color: var(--muted); background: #9aa4b21a; }\n  .tag.accent { color: var(--accent); background: #7c9cff1a; }\n  .tag.bad    { color: var(--bad); background: #f0883e1a; }\n\n  .bar-cell { flex: 1 1 190px; min-width: 165px; }\n  .track { position: relative; height: 24px; background: var(--rail);\n    border: 1px solid var(--line); border-radius: 7px; overflow: hidden; }\n  .fill { position: absolute; inset: 0 auto 0 0; width: 0;\n    background: linear-gradient(90deg, #7c9cff88, var(--accent)); }\n  .fill.ok  { background: linear-gradient(90deg, #3fb95088, var(--good)); }\n  .fill.bad { background: linear-gradient(90deg, #f0883e88, var(--bad)); }\n  .stamp { position: absolute; top: 50%; right: 8px; transform: translateY(-50%);\n    font-size: .74rem; font-variant-numeric: tabular-nums; color: var(--muted);\n    font-weight: 600; }\n  .track.settled .stamp { color: var(--ink); }\n  .name-cell.decider .nm { color: var(--accent); }\n\n  .lat-cell { flex: 0 0 auto; }\n  .lat-cell label { color: var(--muted); font-size: .74rem; display: flex; flex-direction: column;\n    gap: 3px; }\n  .lat-cell .row { display: flex; align-items: center; gap: 8px; }\n  input[type=range] { accent-color: var(--accent); width: 108px; }\n  .lat-cell .val { color: var(--ink); font-variant-numeric: tabular-nums; font-size: .78rem;\n    min-width: 52px; }\n\n  .fail-cell label { display: inline-flex; align-items: center; gap: 7px; cursor: pointer;\n    color: var(--muted); font-size: .8rem; user-select: none; }\n  .fail-cell input { width: 16px; height: 16px; accent-color: var(--bad); cursor: pointer; }\n  .fail-cell label:has(input:checked) { color: var(--bad); font-weight: 600; }\n\n  \u002F* output *\u002F\n  .status { font-size: .9rem; line-height: 1.5; margin: 0 0 12px; color: var(--ink);\n    display: flex; gap: 8px; }\n  .status .dot { flex: 0 0 auto; margin-top: .15em; }\n  .status.resolve .dot { color: var(--good); }\n  .status.reject .dot { color: var(--bad); }\n  .status .idle { color: var(--muted); }\n  .status code { color: var(--accent); background: #ffffff10; padding: 1px 5px; border-radius: 5px; }\n\n  pre { margin: 0; overflow-x: auto; background: var(--rail); border: 1px solid var(--line);\n    border-radius: 10px; padding: 12px; font-size: .78rem; line-height: 1.55; }\n  code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }\n  .k { color: var(--accent); } .c { color: #6b7688; } .v { color: var(--good); } .e { color: var(--bad); }\n\n  .legend { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 12px;\n    font-size: .74rem; color: var(--muted); }\n  .legend span { display: inline-flex; align-items: center; gap: 6px; }\n  .sw { width: 11px; height: 11px; border-radius: 3px; display: inline-block; }\n\n  @media (max-width: 520px) {\n    .name-cell { width: 100%; }\n    .lat-cell, .fail-cell { flex: 1 1 auto; }\n    input[type=range] { width: 100%; }\n  }","\"use strict\";\n  const $ = (s, r = document) => r.querySelector(s);\n  const $$ = (s, r = document) => [...r.querySelectorAll(s)];\n\n  \u002F\u002F ---- Mock \"APIs\". No network — setTimeout simulates latency. ----\n  const REQUESTS = [\n    { key: \"users\",    name: \"Users\",    value: '{ count: 1284, new: 37 }',    reason: \"Users API 503\" },\n    { key: \"revenue\",  name: \"Revenue\",  value: '{ mrr: 92400, currency: \"USD\" }', reason: \"Revenue API 500\" },\n    { key: \"alerts\",   name: \"Alerts\",   value: '[ { level: \"warn\", msg: \"disk 82%\" } ]', reason: \"Alerts API 500\" },\n    { key: \"activity\", name: \"Activity\", value: '{ events: 512, live: 8 }',    reason: \"Activity API timeout\" },\n  ];\n\n  const METHODS = {\n    all: {\n      label: \"Promise.all\",\n      desc: 'Rejects the \u003Cem>moment\u003C\u002Fem> any one promise fails — and discards every other result. Use it only when partial success is meaningless (atomic writes, \"need all or nothing\").',\n    },\n    allSettled: {\n      label: \"Promise.allSettled\",\n      desc: 'Never rejects. Waits for all to finish and reports each outcome as \u003Ccode>{ status }\u003C\u002Fcode>. The right tool for dashboards & partial results — one dead API can\\'t sink the rest.',\n    },\n    any: {\n      label: \"Promise.any\",\n      desc: 'Resolves with the \u003Cstrong>first success\u003C\u002Fstrong>, ignoring failures. Rejects only if \u003Cem>all\u003C\u002Fem> fail (an \u003Ccode>AggregateError\u003C\u002Fcode>). Right for failover \u002F redundant sources.',\n    },\n    race: {\n      label: \"Promise.race\",\n      desc: 'Settles on the \u003Cstrong>first promise to finish\u003C\u002Fstrong> — success \u003Cem>or\u003C\u002Fem> failure. The classic way to impose a timeout on something that lacks one.',\n    },\n  };\n\n  const PRESETS = {\n    succeed: { latency: [600, 1200, 900, 1500], fail: [false, false, false, false] },\n    alerts:  { latency: [600, 1000, 800, 1400], fail: [false, false, true,  false] },\n    slow:    { latency: [500, 700,  900, 3000], fail: [false, false, false, false] },\n    allfail: { latency: [700, 1100, 500, 1300], fail: [true,  true,  true,  true ] },\n  };\n\n  \u002F\u002F ---- Build request rows ----\n  const rowsEl = $(\"#rows\");\n  const els = REQUESTS.map((r, i) => {\n    const row = document.createElement(\"div\");\n    row.className = \"req\";\n    row.innerHTML = `\n      \u003Cdiv class=\"name-cell\">\n        \u003Cdiv class=\"nm\">${r.name}\u003C\u002Fdiv>\n        \u003Cspan class=\"tag\" hidden>\u003C\u002Fspan>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"bar-cell\">\n        \u003Cdiv class=\"track\">\u003Cdiv class=\"fill\">\u003C\u002Fdiv>\u003Cspan class=\"stamp\">\u003C\u002Fspan>\u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"lat-cell\">\n        \u003Clabel for=\"lat-${r.key}\">Latency\n          \u003Cspan class=\"row\">\n            \u003Cinput type=\"range\" id=\"lat-${r.key}\" min=\"200\" max=\"3000\" step=\"100\" value=\"600\" \u002F>\n            \u003Cspan class=\"val\" id=\"latv-${r.key}\">600 ms\u003C\u002Fspan>\n          \u003C\u002Fspan>\n        \u003C\u002Flabel>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"fail-cell\">\n        \u003Clabel>\u003Cinput type=\"checkbox\" id=\"fail-${r.key}\" \u002F> make it fail\u003C\u002Flabel>\n      \u003C\u002Fdiv>`;\n    rowsEl.appendChild(row);\n    return {\n      row,\n      nameCell: $(\".name-cell\", row),\n      tag: $(\".tag\", row),\n      track: $(\".track\", row),\n      fill: $(\".fill\", row),\n      stamp: $(\".stamp\", row),\n      lat: $(`#lat-${r.key}`, row),\n      latv: $(`#latv-${r.key}`, row),\n      fail: $(`#fail-${r.key}`, row),\n    };\n  });\n\n  els.forEach((e) => {\n    e.lat.addEventListener(\"input\", () => { e.latv.textContent = e.lat.value + \" ms\"; clearIdleBars(); });\n    e.fail.addEventListener(\"change\", clearIdleBars);\n  });\n\n  function getInputs() {\n    return REQUESTS.map((r, i) => ({\n      ...r, index: i, latency: +els[i].lat.value, fail: els[i].fail.checked,\n    }));\n  }\n\n  \u002F\u002F ---- Method selection ----\n  let method = \"all\";\n  function selectMethod(m) {\n    method = m;\n    $$(\".seg button\").forEach((b) => b.setAttribute(\"aria-pressed\", String(b.dataset.method === m)));\n    $(\"#methodDesc\").innerHTML = METHODS[m].desc;\n    reset();\n  }\n  $$(\".seg button\").forEach((b) => b.addEventListener(\"click\", () => selectMethod(b.dataset.method)));\n\n  \u002F\u002F ---- Presets ----\n  $$(\".presets button\").forEach((b) =>\n    b.addEventListener(\"click\", () => {\n      const p = PRESETS[b.dataset.preset];\n      els.forEach((e, i) => {\n        e.lat.value = p.latency[i]; e.latv.textContent = p.latency[i] + \" ms\";\n        e.fail.checked = p.fail[i];\n      });\n      reset();\n    })\n  );\n\n  \u002F\u002F ---- Aggregate semantics (deterministic from the inputs) ----\n  function firstToSettle(inputs, pred) {\n    let best = -1;\n    inputs.forEach((r, i) => { if (pred(r) && (best \u003C 0 || r.latency \u003C inputs[best].latency)) best = i; });\n    return best;\n  }\n\n  function computeAggregate(inputs) {\n    const maxLat = Math.max(...inputs.map((r) => r.latency));\n\n    if (method === \"all\") {\n      const failIdx = firstToSettle(inputs, (r) => r.fail);\n      if (failIdx >= 0) return { settleTime: inputs[failIdx].latency, status: \"reject\", decider: failIdx };\n      return { settleTime: maxLat, status: \"resolve\", decider: null };\n    }\n    if (method === \"allSettled\") {\n      return { settleTime: maxLat, status: \"resolve\", decider: null };\n    }\n    if (method === \"any\") {\n      const okIdx = firstToSettle(inputs, (r) => !r.fail);\n      if (okIdx >= 0) return { settleTime: inputs[okIdx].latency, status: \"resolve\", decider: okIdx };\n      return { settleTime: maxLat, status: \"reject\", decider: null };\n    }\n    \u002F\u002F race\n    const idx = firstToSettle(inputs, () => true);\n    return { settleTime: inputs[idx].latency, status: inputs[idx].fail ? \"reject\" : \"resolve\", decider: idx };\n  }\n\n  \u002F\u002F Per-request role once the group has settled.\n  function classify(inputs, agg, i) {\n    const r = inputs[i];\n    if (method === \"allSettled\")\n      return r.fail ? { label: \"rejected · reported\", tone: \"bad\" } : { label: \"fulfilled · reported\", tone: \"used\" };\n    if (method === \"all\") {\n      if (agg.status === \"resolve\") return { label: \"value used\", tone: \"used\" };\n      return i === agg.decider ? { label: \"✗ rejected the group\", tone: \"bad\" } : { label: \"discarded\", tone: \"discard\" };\n    }\n    if (method === \"any\") {\n      if (agg.status === \"resolve\")\n        return i === agg.decider ? { label: \"★ winner\", tone: \"accent\" }\n          : { label: r.fail ? \"failure ignored\" : \"discarded\", tone: \"discard\" };\n      return { label: \"→ AggregateError\", tone: \"bad\" };\n    }\n    \u002F\u002F race\n    if (i === agg.decider)\n      return agg.status === \"resolve\" ? { label: \"★ won the race\", tone: \"accent\" } : { label: \"✗ settled first (failed)\", tone: \"bad\" };\n    return { label: \"discarded\", tone: \"discard\" };\n  }\n\n  \u002F\u002F ---- Output rendering ----\n  const kw = (t) => `\u003Cspan class=\"k\">${t}\u003C\u002Fspan>`;\n  const cm = (t) => `\u003Cspan class=\"c\">${t}\u003C\u002Fspan>`;\n  const vv = (t) => `\u003Cspan class=\"v\">${t}\u003C\u002Fspan>`;\n  const ee = (t) => `\u003Cspan class=\"e\">${t}\u003C\u002Fspan>`;\n\n  function buildOutput(inputs, agg) {\n    const winner = agg.decider != null ? inputs[agg.decider] : null;\n    if (method === \"all\") {\n      if (agg.status === \"resolve\") {\n        const body = inputs.map((r) => `  ${vv(r.value)},${\" \".repeat(Math.max(1, 34 - r.value.length))}${cm(\"\u002F\u002F \" + r.name)}`).join(\"\\n\");\n        return `${cm(\"\u002F\u002F ✅ Promise.all resolved — all four succeeded\")}\\n[\\n${body}\\n]`;\n      }\n      return `${cm(\"\u002F\u002F ❌ Promise.all rejected on first failure\")}\\n${ee(\"Error: \" + winner.reason)}\\n${cm(\"\u002F\u002F every other result — even the ones already resolved — was discarded\")}`;\n    }\n    if (method === \"allSettled\") {\n      const body = inputs.map((r) => {\n        const obj = r.fail\n          ? `{ status: ${vv('\"rejected\"')},  reason: ${ee(\"Error: \" + r.reason)} }`\n          : `{ status: ${vv('\"fulfilled\"')}, value: ${vv(r.value)} }`;\n        return `  ${obj},  ${cm(\"\u002F\u002F \" + r.name)}`;\n      }).join(\"\\n\");\n      return `${cm(\"\u002F\u002F ✅ Promise.allSettled resolved (it never rejects)\")}\\n[\\n${body}\\n]`;\n    }\n    if (method === \"any\") {\n      if (agg.status === \"resolve\")\n        return `${cm(\"\u002F\u002F ✅ Promise.any — first success wins, failures ignored\")}\\n${vv(winner.value)}   ${cm(\"\u002F\u002F \" + winner.name + \" won at \" + agg.settleTime + \" ms\")}`;\n      const body = inputs.map((r) => `  ├ ${r.name}: ${ee(\"Error: \" + r.reason)}`).join(\"\\n\");\n      return `${cm(\"\u002F\u002F ❌ Promise.any — every promise failed\")}\\n${ee(\"AggregateError: All promises were rejected\")}\\n${body}`;\n    }\n    \u002F\u002F race\n    if (agg.status === \"resolve\")\n      return `${cm(\"\u002F\u002F ✅ Promise.race — first to settle, and it succeeded\")}\\n${vv(winner.value)}   ${cm(\"\u002F\u002F \" + winner.name + \" finished first at \" + agg.settleTime + \" ms\")}`;\n    return `${cm(\"\u002F\u002F ❌ Promise.race — first to settle, and it failed\")}\\n${ee(\"Error: \" + winner.reason)}   ${cm(\"\u002F\u002F \" + winner.name + \" settled first at \" + agg.settleTime + \" ms\")}`;\n  }\n\n  \u002F\u002F Plain-English narration of why the group settled the way it did.\n  function buildNarrative(inputs, agg) {\n    const t = agg.settleTime;\n    const M = `\u003Ccode>Promise.${method}\u003C\u002Fcode>`;\n    if (method === \"all\") {\n      if (agg.status === \"resolve\")\n        return `${M} waited for the slowest request and resolved at \u003Cstrong>${t} ms\u003C\u002Fstrong> with all four values. It is only ever as fast as its slowest member.`;\n      const arrived = inputs.filter((r) => !r.fail && r.latency \u003C t).map((r) => r.name);\n      const thrown = arrived.length\n        ? `The results from \u003Cstrong>${arrived.join(\" and \")}\u003C\u002Fstrong> had already arrived — and were thrown away.`\n        : `No other results had even arrived yet.`;\n      return `${M} rejected the instant \u003Cstrong>${inputs[agg.decider].name}\u003C\u002Fstrong> failed at \u003Cstrong>${t} ms\u003C\u002Fstrong>. ${thrown}`;\n    }\n    if (method === \"allSettled\") {\n      const failed = inputs.filter((r) => r.fail).map((r) => r.name);\n      const part = failed.length\n        ? `\u003Cstrong>${failed.join(\", \")}\u003C\u002Fstrong> ${failed.length > 1 ? \"are\" : \"is\"} reported as rejected, while the others keep their values.`\n        : `all four are reported as fulfilled.`;\n      return `${M} waited for every request (\u003Cstrong>${t} ms\u003C\u002Fstrong>) and never rejected — ${part}`;\n    }\n    if (method === \"any\") {\n      if (agg.status === \"resolve\") {\n        const ignored = inputs.filter((r) => r.fail && r.latency \u003C t).map((r) => r.name);\n        const ig = ignored.length ? ` It ignored \u003Cstrong>${ignored.join(\", \")}\u003C\u002Fstrong> failing earlier and kept waiting for a success.` : \"\";\n        return `${M} resolved with \u003Cstrong>${inputs[agg.decider].name}\u003C\u002Fstrong>, the first request to succeed (\u003Cstrong>${t} ms\u003C\u002Fstrong>).${ig}`;\n      }\n      return `${M} rejected at \u003Cstrong>${t} ms\u003C\u002Fstrong> — every request failed, so it threw an \u003Ccode>AggregateError\u003C\u002Fcode> wrapping all four reasons.`;\n    }\n    \u002F\u002F race\n    const w = inputs[agg.decider];\n    if (agg.status === \"resolve\")\n      return `${M} settled on the first to finish: \u003Cstrong>${w.name}\u003C\u002Fstrong> at \u003Cstrong>${t} ms\u003C\u002Fstrong> — a success. The other three were discarded.`;\n    return `${M} settled on the first to finish: \u003Cstrong>${w.name}\u003C\u002Fstrong> at \u003Cstrong>${t} ms\u003C\u002Fstrong> — a \u003Cem>failure\u003C\u002Fem>. Because \u003Ccode>race\u003C\u002Fcode> stops at the first settle either way, that error won.`;\n  }\n\n  \u002F\u002F ---- Run engine ----\n  let timers = [];\n  let raf = 0;\n  let running = false;\n\n  function setControlsDisabled(d) {\n    els.forEach((e) => { e.lat.disabled = d; e.fail.disabled = d; });\n    $$(\".seg button\").forEach((b) => (b.disabled = d));\n    $$(\".presets button\").forEach((b) => (b.disabled = d));\n    $(\"#run\").disabled = d;\n  }\n\n  function clearIdleBars() {\n    if (running) return;\n    els.forEach((e) => resetBar(e));\n    $(\"#status\").className = \"status\";\n    $(\"#statusText\").className = \"idle\";\n    $(\"#statusText\").innerHTML = \"Inputs changed — press \u003Cstrong>Run\u003C\u002Fstrong> to fire them again.\";\n    const out = $(\"#output\"); out.className = \"c\"; out.textContent = \"\u002F\u002F the resolved value(s) or the rejection will appear here\";\n  }\n\n  function resetBar(e) {\n    e.fill.style.transition = \"none\";\n    e.fill.style.width = \"0%\";\n    e.fill.className = \"fill\";\n    e.track.classList.remove(\"settled\");\n    e.stamp.textContent = \"\";\n    e.tag.hidden = true;\n    e.tag.className = \"tag\";\n    e.row.classList.remove(\"dim\");\n    e.nameCell.classList.remove(\"decider\");\n  }\n\n  function reset() {\n    timers.forEach(clearTimeout); timers = [];\n    cancelAnimationFrame(raf);\n    running = false;\n    setControlsDisabled(false);\n    $(\"#run\").textContent = \"▶ Run\";\n    $(\"#clock\").textContent = \"0 ms\";\n    els.forEach(resetBar);\n    $(\"#status\").className = \"status\";\n    $(\"#statusText\").className = \"idle\";\n    $(\"#statusText\").innerHTML = \"Press \u003Cstrong>Run\u003C\u002Fstrong> to fire all four requests concurrently.\";\n    const out = $(\"#output\"); out.className = \"c\"; out.textContent = \"\u002F\u002F the resolved value(s) or the rejection will appear here\";\n  }\n\n  function run() {\n    reset();\n    running = true;\n    setControlsDisabled(true);\n    $(\"#run\").disabled = true;\n\n    const inputs = getInputs();\n    const agg = computeAggregate(inputs);\n    const maxLat = Math.max(...inputs.map((r) => r.latency));\n    const start = performance.now();\n\n    \u002F\u002F Kick every progress bar off at once (concurrency!).\n    els.forEach((e, i) => {\n      const lat = inputs[i].latency;\n      e.stamp.textContent = lat + \" ms\";\n      \u002F\u002F force reflow so the 0% start is committed before we animate to 100%\n      void e.fill.offsetWidth;\n      e.fill.style.transition = `width ${lat}ms linear`;\n      requestAnimationFrame(() => (e.fill.style.width = \"100%\"));\n    });\n\n    \u002F\u002F Live elapsed clock.\n    const tick = () => {\n      const el = Math.min(performance.now() - start, maxLat);\n      $(\"#clock\").textContent = Math.round(el) + \" ms\";\n      if (el \u003C maxLat) raf = requestAnimationFrame(tick);\n    };\n    raf = requestAnimationFrame(tick);\n\n    \u002F\u002F Each request settles at its own latency.\n    inputs.forEach((r, i) => {\n      timers.push(setTimeout(() => {\n        const e = els[i];\n        const ok = !r.fail;\n        e.fill.className = \"fill \" + (ok ? \"ok\" : \"bad\");\n        e.track.classList.add(\"settled\");\n        e.stamp.textContent = (ok ? \"✓ \" : \"✗ \") + r.latency + \" ms\";\n        const cls = classify(inputs, agg, i);\n        e.tag.textContent = cls.label;\n        e.tag.className = \"tag \" + cls.tone;\n        e.tag.hidden = false;\n        if (cls.tone === \"discard\") e.row.classList.add(\"dim\");\n      }, r.latency));\n    });\n\n    \u002F\u002F The MOMENT the aggregate settles — reveal the result.\n    timers.push(setTimeout(() => {\n      if (agg.decider != null) els[agg.decider].nameCell.classList.add(\"decider\");\n      $(\"#status\").className = \"status \" + agg.status;\n      $(\"#status .dot\").textContent = agg.status === \"resolve\" ? \"✓\" : \"✗\";\n      $(\"#statusText\").className = \"\";\n      $(\"#statusText\").innerHTML = buildNarrative(inputs, agg);\n      const out = $(\"#output\");\n      out.className = \"\";\n      out.innerHTML = buildOutput(inputs, agg);\n    }, agg.settleTime));\n\n    \u002F\u002F When the last request finishes animating, let the reader tinker again.\n    timers.push(setTimeout(() => {\n      running = false;\n      setControlsDisabled(false);\n      $(\"#run\").disabled = false;\n      $(\"#run\").textContent = \"▶ Run again\";\n      $(\"#clock\").textContent = maxLat + \" ms\";\n    }, maxLat + 40));\n  }\n\n  $(\"#run\").addEventListener(\"click\", run);\n  $(\"#reset\").addEventListener(\"click\", reset);\n\n  \u002F\u002F ---- Init: the post's opening scenario (all + Alerts fails) ----\n  (function init() {\n    const p = PRESETS.alerts;\n    els.forEach((e, i) => {\n      e.lat.value = p.latency[i]; e.latv.textContent = p.latency[i] + \" ms\"; e.fail.checked = p.fail[i];\n    });\n    selectMethod(\"all\");\n  })();",{"height":40,"autorun":17},520,{"slug":33,"title":42,"excerpt":43,"coverUrl":44},"You reach for `Promise.all` for every concurrent request. Here's when to use the other three.","`Promise.all` fails the moment any one request fails. `allSettled`, `any`, and `race` each solve a different concurrency problem — dashboard partial results, CDN failover, and timeouts. Here's the taxonomy.","\u002Fmedia\u002Fcovers\u002Fpromise-concurrency-all-settled-any-race.png"]