Promise.resolve()
✔ What it does
Creates an already resolved promise.
✔ Example
const p = Promise.resolve("Success!");
p.then(res => console.log(res));Success!✔ Use Case
Convert normal values into promises
Testing async flow
Return resolved values inside async functions
Promise.reject()
✔ What it does
Creates an already rejected promise.
✔ Example
const p = Promise.reject("Something went wrong!");
p.catch(err => console.log(err));Something went wrong!Promise.all()
✔ What it does
Runs multiple promises in parallel → Returns only if all succeed.
✔ Example
const p1 = Promise.resolve(10);
const p2 = Promise.resolve(20);
const p3 = Promise.resolve(30);
Promise.all([p1, p2, p3])
.then(result => console.log(result))
.catch(err => console.log("Error:", err));[10, 20, 30]❗ If one promise fails
Promise.all([
Promise.resolve("A"),
Promise.reject("Failed"),
Promise.resolve("C")
]).catch(err => console.log(err));FailedPromise.allSettled()
✔ What it does
Waits for all promises, even if some fail.
Returns the status of each promise.
✔ Example
const p1 = Promise.resolve("OK");
const p2 = Promise.reject("Error occured");
const p3 = Promise.resolve("Done");
Promise.allSettled([p1, p2, p3])
.then(result => console.log(result));[
{ status: 'fulfilled', value: 'OK' },
{ status: 'rejected', reason: 'Error occured' },
{ status: 'fulfilled', value: 'Done' }
]✔ Use Case
When you want all results, not just successful ones (e.g., polling multiple APIs)
Promise.race()
✔ What it does
Returns the first promise that settles
(fulfilled or rejected).
✔ Example
const p1 = new Promise(resolve => setTimeout(() => resolve("Fast!"), 500));
const p2 = new Promise(resolve => setTimeout(() => resolve("Slow"), 1500));
Promise.race([p1, p2]).then(console.log);Fast!❗ If first settles with rejection
Promise.race([
Promise.reject("Failed first"),
Promise.resolve("Success")
]).catch(console.log);Failed firstPromise.any()
✔ What it does
Returns the first fulfilled (successful) promise.
Ignores rejected ones.
✔ Example
const p1 = Promise.reject("Err 1");
const p2 = Promise.resolve("Data loaded!");
const p3 = Promise.resolve("Another success");
Promise.any([p1, p2, p3])
.then(res => console.log(res))
.catch(err => console.log(err));Data loaded!❗ If all fail
Promise.any([
Promise.reject("A"),
Promise.reject("B")
]).catch(err => console.log(err.errors));["A", "B"]<div class="infographic-promiseapis">
<style>
.infographic-promiseapis {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--good: #1a8a5f;
--good-soft: #e1f2ea;
--bad: #c8452e;
--bad-soft: #f7e3df;
--amber: #a4720a;
--amber-soft: #faf1de;
box-sizing: border-box;
max-width: 880px;
margin: 0 auto;
font-family: 'Inter', system-ui, sans-serif;
color: var(--ink);
background: var(--paper);
overflow-x: hidden;
}
.infographic-promiseapis[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
--good: #4fbf8f;
--good-soft: #16281f;
--bad: #e0715a;
--bad-soft: #2e211d;
--amber: #d9a94a;
--amber-soft: #2c2413;
}
.infographic-promiseapis * { box-sizing: border-box; }
.infographic-promiseapis h1 { font-family: 'Fraunces', Georgia, serif; font-weight: 600; margin: 0; }
.infographic-promiseapis p { margin: 0; }
.infographic-promiseapis button { font-family: inherit; }
.pa2-wrap { padding: clamp(1.25rem, 5vw, 2.5rem) clamp(1.1rem, 5vw, 3rem) 2rem; }
.pa2-hero { text-align: center; margin-bottom: 1.2rem; }
.pa2-hero h1 { font-size: clamp(1.35rem, 4.5vw, 1.85rem); }
.pa2-hero p { color: var(--ink-soft); margin-top: 0.4rem; font-size: 0.82rem; }
.pa2-tabs { display: flex; flex-wrap: wrap; gap: 0.35rem; justify-content: center; margin-bottom: 1.2rem; }
.pa2-tab { border: 1px solid var(--line); background: var(--paper-alt); color: var(--ink-soft); padding: 0.36rem 0.65rem; font-size: 0.68rem; font-weight: 700; cursor: pointer; font-family: 'IBM Plex Mono', monospace; }
.pa2-tab.is-active { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }
.pa2-tab:hover:not(.is-active) { border-color: var(--ink-soft); color: var(--ink); }
.pa2-panel { display: none; }
.pa2-panel.is-active { display: block; }
.pa2-code { border: 1.5px solid var(--line); background: #1e1e1e; color: #d4d4d4; padding: 0.55rem 0.75rem; font-family: 'IBM Plex Mono', monospace; font-size: 0.65rem; line-height: 1.65; margin-bottom: 1rem; white-space: pre; overflow-x: auto; border-radius: 4px; }
.tok-kw { color: #569cd6; }
.tok-fn { color: #dcdcaa; }
.tok-str { color: #ce9178; }
.tok-num { color: #b5cea8; }
.tok-var { color: #9cdcfe; }
.tok-punc { color: #d4d4d4; }
/* generic parallel bars */
.pa2-tasks { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 0.9rem; }
.pa2-task { display: flex; align-items: center; gap: 0.5rem; }
.pa2-task-label { width: 60px; flex-shrink: 0; font-family: 'IBM Plex Mono', monospace; font-size: 0.64rem; color: var(--ink-soft); }
.pa2-task-track { flex: 1; height: 14px; background: var(--paper-alt); border: 1px solid var(--line); position: relative; overflow: hidden; }
.pa2-task-bar { position: absolute; left: 0; top: 0; bottom: 0; width: 0%; background: var(--accent); transition: width linear; }
.pa2-task.good .pa2-task-bar { background: var(--good); }
.pa2-task.bad .pa2-task-bar { background: var(--bad); }
.pa2-task.dim .pa2-task-bar { opacity: 0.3; }
.pa2-task-mark { width: 16px; flex-shrink: 0; text-align: center; font-size: 0.7rem; font-weight: 700; opacity: 0; transition: opacity 0.2s ease; }
.pa2-task.good .pa2-task-mark.chk { opacity: 1; color: var(--good); }
.pa2-task.bad .pa2-task-mark.crs { opacity: 1; color: var(--bad); }
/* result box */
.pa2-result { width: min(360px, 100%); margin: 0 auto; text-align: center; border: 1.5px solid var(--line); background: var(--paper-alt); padding: 0.55rem 0.75rem; transition: border-color 0.35s ease, background 0.35s ease; }
.pa2-result .pa2-rname { font-family: 'IBM Plex Mono', monospace; font-weight: 700; font-size: 0.74rem; }
.pa2-result .pa2-rval { font-family: 'IBM Plex Mono', monospace; font-size: 0.66rem; color: var(--ink-soft); margin-top: 0.3rem; opacity: 0; transition: opacity 0.3s ease; white-space: pre-wrap; }
.pa2-result .pa2-rval.is-shown { opacity: 1; }
.pa2-result.good { border-color: var(--good); background: var(--good-soft); }
.pa2-result.good .pa2-rval { color: var(--good); }
.pa2-result.bad { border-color: var(--bad); background: var(--bad-soft); }
.pa2-result.bad .pa2-rval { color: var(--bad); }
.pa2-toggle-row { display: flex; align-items: center; justify-content: center; gap: 0.5rem; margin-bottom: 0.9rem; flex-wrap: wrap; text-align: center; }
.pa2-toggle-label { font-family: 'IBM Plex Mono', monospace; font-size: 0.64rem; color: var(--ink-soft); }
.pa2-toggle { display: flex; border: 1.5px solid var(--line); overflow: hidden; }
.pa2-toggle button { border: none; background: var(--paper-alt); color: var(--ink-soft); padding: 0.28rem 0.6rem; font-size: 0.62rem; font-weight: 700; cursor: pointer; font-family: 'IBM Plex Mono', monospace; }
.pa2-toggle button.on.is-active { background: var(--bad-soft); color: var(--bad); }
.pa2-toggle button.off.is-active { background: var(--good-soft); color: var(--good); }
.pa2-play { display: block; margin: 1rem auto 0; border: none; background: var(--accent); color: #fff; padding: 0.45rem 1.1rem; font-size: 0.76rem; font-weight: 600; cursor: pointer; }
.pa2-play:active { transform: scale(0.96); }
.pa2-play:disabled { opacity: 0.45; cursor: default; }
/* instant badge (resolve/reject tabs) */
.pa2-instant-row { display: flex; justify-content: center; margin-bottom: 0.9rem; }
.pa2-instant-card { width: 220px; text-align: center; border: 1.5px solid var(--line); background: var(--paper-alt); padding: 0.65rem 0.7rem; transition: border-color 0.35s ease, background 0.35s ease; }
.pa2-instant-card .pa2-badge { display: inline-flex; align-items: center; gap: 0.3rem; margin-top: 0.5rem; font-family: 'IBM Plex Mono', monospace; font-size: 0.66rem; font-weight: 700; padding: 0.22rem 0.55rem; border: 1.5px solid var(--line); color: var(--ink-soft); }
.pa2-instant-card.good .pa2-badge { border-color: var(--good); color: var(--good); background: var(--good-soft); }
.pa2-instant-card.bad .pa2-badge { border-color: var(--bad); color: var(--bad); background: var(--bad-soft); }
/* request -> processing -> settle pipeline */
.pa2-pipeline { display: flex; align-items: center; justify-content: center; gap: 0; margin-bottom: 1rem; }
.pa2-pstep { display: flex; flex-direction: column; align-items: center; gap: 0.3rem; width: 92px; }
.pa2-pstep .pa2-pdot { width: 34px; height: 34px; border-radius: 50%; border: 1.5px solid var(--line); background: var(--paper-alt); display: flex; align-items: center; justify-content: center; font-size: 0.9rem; transition: border-color 0.25s ease, background 0.25s ease, transform 0.25s ease, color 0.25s ease; color: var(--ink-soft); }
.pa2-pstep .pa2-plabel { font-size: 0.6rem; color: var(--ink-soft); text-align: center; }
.pa2-pstep.is-active .pa2-pdot { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); transform: scale(1.12); }
.pa2-pstep.is-active .pa2-plabel { color: var(--ink); font-weight: 600; }
.pa2-pstep.is-processing .pa2-pdot { animation: pa2-spin 0.9s linear infinite; }
@keyframes pa2-spin { to { transform: rotate(360deg); } }
.pa2-pstep.is-good .pa2-pdot { border-color: var(--good); background: var(--good-soft); color: var(--good); transform: scale(1.12); animation: none; }
.pa2-pstep.is-good .pa2-plabel { color: var(--good); font-weight: 700; }
.pa2-pstep.is-bad .pa2-pdot { border-color: var(--bad); background: var(--bad-soft); color: var(--bad); transform: scale(1.12); animation: none; }
.pa2-pstep.is-bad .pa2-plabel { color: var(--bad); font-weight: 700; }
.pa2-pconnect { flex: 1; max-width: 40px; height: 2px; background: var(--line); position: relative; top: -14px; }
.pa2-pconnect-fill { position: absolute; left: 0; top: 0; bottom: 0; width: 0%; background: var(--accent); transition: width 0.35s ease; }
@media (prefers-reduced-motion: reduce) {
.infographic-promiseapis *, .infographic-promiseapis *::before, .infographic-promiseapis *::after {
animation-duration: 0.001ms !important; transition-duration: 0.001ms !important;
}
}
</style>
<div class="pa2-wrap">
<div class="pa2-hero">
<h1>Promise combinators</h1>
<p>Six ways to turn multiple promises into one.</p>
</div>
<div class="pa2-tabs">
<button class="pa2-tab is-active" data-tab="resolve" type="button">.resolve()</button>
<button class="pa2-tab" data-tab="reject" type="button">.reject()</button>
<button class="pa2-tab" data-tab="all" type="button">.all()</button>
<button class="pa2-tab" data-tab="allsettled" type="button">.allSettled()</button>
<button class="pa2-tab" data-tab="race" type="button">.race()</button>
<button class="pa2-tab" data-tab="any" type="button">.any()</button>
</div>
<!-- resolve -->
<div class="pa2-panel is-active" data-panel="resolve">
<div class="pa2-code"><span class="tok-var">Promise</span><span class="tok-punc">.</span><span class="tok-fn">resolve</span><span class="tok-punc">(</span><span class="tok-str">"Success!"</span><span class="tok-punc">)</span>
<span class="tok-punc">.</span><span class="tok-fn">then</span><span class="tok-punc">(</span><span class="tok-var">res</span> <span class="tok-punc">=></span> <span class="tok-var">console</span><span class="tok-punc">.</span><span class="tok-fn">log</span><span class="tok-punc">(</span><span class="tok-var">res</span><span class="tok-punc">));</span></div>
<div class="pa2-pipeline" id="rsPipeline">
<div class="pa2-pstep" id="rsStep1">
<div class="pa2-pdot">✉</div>
<div class="pa2-plabel">request</div>
</div>
<div class="pa2-pconnect" id="rsConn1"><div class="pa2-pconnect-fill"></div></div>
<div class="pa2-pstep" id="rsStep2">
<div class="pa2-pdot">◌</div>
<div class="pa2-plabel">processing</div>
</div>
<div class="pa2-pconnect" id="rsConn2"><div class="pa2-pconnect-fill"></div></div>
<div class="pa2-pstep" id="rsStep3">
<div class="pa2-pdot">✓</div>
<div class="pa2-plabel">resolved</div>
</div>
</div>
<div class="pa2-instant-row">
<div class="pa2-instant-card" id="rsCard">
<div class="pa2-rname" style="font-family:'IBM Plex Mono',monospace;font-weight:700;">the promise</div>
<div class="pa2-badge" id="rsBadge">idle</div>
</div>
</div>
<button class="pa2-play" data-run="resolve" type="button">run</button>
</div>
<!-- reject -->
<div class="pa2-panel" data-panel="reject">
<div class="pa2-code"><span class="tok-var">Promise</span><span class="tok-punc">.</span><span class="tok-fn">reject</span><span class="tok-punc">(</span><span class="tok-str">"Something went wrong!"</span><span class="tok-punc">)</span>
<span class="tok-punc">.</span><span class="tok-fn">catch</span><span class="tok-punc">(</span><span class="tok-var">err</span> <span class="tok-punc">=></span> <span class="tok-var">console</span><span class="tok-punc">.</span><span class="tok-fn">log</span><span class="tok-punc">(</span><span class="tok-var">err</span><span class="tok-punc">));</span></div>
<div class="pa2-pipeline" id="rjPipeline">
<div class="pa2-pstep" id="rjStep1">
<div class="pa2-pdot">✉</div>
<div class="pa2-plabel">request</div>
</div>
<div class="pa2-pconnect" id="rjConn1"><div class="pa2-pconnect-fill"></div></div>
<div class="pa2-pstep" id="rjStep2">
<div class="pa2-pdot">◌</div>
<div class="pa2-plabel">processing</div>
</div>
<div class="pa2-pconnect" id="rjConn2"><div class="pa2-pconnect-fill"></div></div>
<div class="pa2-pstep" id="rjStep3">
<div class="pa2-pdot">✕</div>
<div class="pa2-plabel">rejected</div>
</div>
</div>
<div class="pa2-instant-row">
<div class="pa2-instant-card" id="rjCard">
<div class="pa2-rname" style="font-family:'IBM Plex Mono',monospace;font-weight:700;">the promise</div>
<div class="pa2-badge" id="rjBadge">idle</div>
</div>
</div>
<button class="pa2-play" data-run="reject" type="button">run</button>
</div>
<!-- all -->
<div class="pa2-panel" data-panel="all">
<div class="pa2-code"><span class="tok-var">Promise</span><span class="tok-punc">.</span><span class="tok-fn">all</span><span class="tok-punc">([</span><span class="tok-var">p1</span><span class="tok-punc">,</span> <span class="tok-var">p2</span><span class="tok-punc">,</span> <span class="tok-var">p3</span><span class="tok-punc">])</span>
<span class="tok-punc">.</span><span class="tok-fn">then</span><span class="tok-punc">(</span><span class="tok-var">res</span> <span class="tok-punc">=></span> <span class="tok-var">console</span><span class="tok-punc">.</span><span class="tok-fn">log</span><span class="tok-punc">(</span><span class="tok-var">res</span><span class="tok-punc">))</span>
<span class="tok-punc">.</span><span class="tok-fn">catch</span><span class="tok-punc">(</span><span class="tok-var">err</span> <span class="tok-punc">=></span> <span class="tok-var">console</span><span class="tok-punc">.</span><span class="tok-fn">log</span><span class="tok-punc">(</span><span class="tok-str">"Error:"</span><span class="tok-punc">,</span> <span class="tok-var">err</span><span class="tok-punc">));</span></div>
<div class="pa2-toggle-row">
<span class="pa2-toggle-label">p2 rejects?</span>
<div class="pa2-toggle" id="allToggle">
<button class="off is-active" data-val="off" type="button">no</button>
<button class="on" data-val="on" type="button">yes</button>
</div>
</div>
<div class="pa2-tasks">
<div class="pa2-task" id="allT1"><div class="pa2-task-label">p1</div><div class="pa2-task-track"><div class="pa2-task-bar"></div></div><div class="pa2-task-mark chk">✓</div></div>
<div class="pa2-task" id="allT2"><div class="pa2-task-label">p2</div><div class="pa2-task-track"><div class="pa2-task-bar"></div></div><div class="pa2-task-mark chk">✓</div><div class="pa2-task-mark crs">✕</div></div>
<div class="pa2-task" id="allT3"><div class="pa2-task-label">p3</div><div class="pa2-task-track"><div class="pa2-task-bar"></div></div><div class="pa2-task-mark chk">✓</div></div>
</div>
<div class="pa2-result" id="allResult"><div class="pa2-rname">Promise.all</div><div class="pa2-rval" id="allResultVal"></div></div>
<button class="pa2-play" data-run="all" type="button">run</button>
</div>
<!-- allSettled -->
<div class="pa2-panel" data-panel="allsettled">
<div class="pa2-code"><span class="tok-var">Promise</span><span class="tok-punc">.</span><span class="tok-fn">allSettled</span><span class="tok-punc">([</span><span class="tok-var">p1</span><span class="tok-punc">,</span> <span class="tok-var">p2</span><span class="tok-punc">,</span> <span class="tok-var">p3</span><span class="tok-punc">])</span>
<span class="tok-punc">.</span><span class="tok-fn">then</span><span class="tok-punc">(</span><span class="tok-var">res</span> <span class="tok-punc">=></span> <span class="tok-var">console</span><span class="tok-punc">.</span><span class="tok-fn">log</span><span class="tok-punc">(</span><span class="tok-var">res</span><span class="tok-punc">));</span></div>
<div class="pa2-tasks">
<div class="pa2-task" id="asT1"><div class="pa2-task-label">p1 "OK"</div><div class="pa2-task-track"><div class="pa2-task-bar"></div></div><div class="pa2-task-mark chk">✓</div></div>
<div class="pa2-task" id="asT2"><div class="pa2-task-label">p2 err</div><div class="pa2-task-track"><div class="pa2-task-bar"></div></div><div class="pa2-task-mark crs">✕</div></div>
<div class="pa2-task" id="asT3"><div class="pa2-task-label">p3 "Done"</div><div class="pa2-task-track"><div class="pa2-task-bar"></div></div><div class="pa2-task-mark chk">✓</div></div>
</div>
<div class="pa2-result" id="asResult"><div class="pa2-rname">Promise.allSettled</div><div class="pa2-rval" id="asResultVal"></div></div>
<button class="pa2-play" data-run="allsettled" type="button">run</button>
</div>
<!-- race -->
<div class="pa2-panel" data-panel="race">
<div class="pa2-code"><span class="tok-var">Promise</span><span class="tok-punc">.</span><span class="tok-fn">race</span><span class="tok-punc">([</span><span class="tok-var">p1</span><span class="tok-punc">,</span> <span class="tok-var">p2</span><span class="tok-punc">])</span>
<span class="tok-punc">.</span><span class="tok-fn">then</span><span class="tok-punc">(</span><span class="tok-var">console</span><span class="tok-punc">.</span><span class="tok-var">log</span><span class="tok-punc">)</span>
<span class="tok-punc">.</span><span class="tok-fn">catch</span><span class="tok-punc">(</span><span class="tok-var">console</span><span class="tok-punc">.</span><span class="tok-var">log</span><span class="tok-punc">);</span></div>
<div class="pa2-toggle-row">
<span class="pa2-toggle-label">fastest one rejects?</span>
<div class="pa2-toggle" id="raceToggle">
<button class="off is-active" data-val="off" type="button">no</button>
<button class="on" data-val="on" type="button">yes</button>
</div>
</div>
<div class="pa2-tasks">
<div class="pa2-task" id="raceT1"><div class="pa2-task-label">p1 fast</div><div class="pa2-task-track"><div class="pa2-task-bar"></div></div><div class="pa2-task-mark chk">✓</div><div class="pa2-task-mark crs">✕</div></div>
<div class="pa2-task" id="raceT2"><div class="pa2-task-label">p2 slow</div><div class="pa2-task-track"><div class="pa2-task-bar"></div></div><div class="pa2-task-mark chk">✓</div></div>
</div>
<div class="pa2-result" id="raceResult"><div class="pa2-rname">Promise.race</div><div class="pa2-rval" id="raceResultVal"></div></div>
<button class="pa2-play" data-run="race" type="button">run</button>
</div>
<!-- any -->
<div class="pa2-panel" data-panel="any">
<div class="pa2-code"><span class="tok-var">Promise</span><span class="tok-punc">.</span><span class="tok-fn">any</span><span class="tok-punc">([</span><span class="tok-var">p1</span><span class="tok-punc">,</span> <span class="tok-var">p2</span><span class="tok-punc">,</span> <span class="tok-var">p3</span><span class="tok-punc">])</span>
<span class="tok-punc">.</span><span class="tok-fn">then</span><span class="tok-punc">(</span><span class="tok-var">res</span> <span class="tok-punc">=></span> <span class="tok-var">console</span><span class="tok-punc">.</span><span class="tok-fn">log</span><span class="tok-punc">(</span><span class="tok-var">res</span><span class="tok-punc">))</span>
<span class="tok-punc">.</span><span class="tok-fn">catch</span><span class="tok-punc">(</span><span class="tok-var">err</span> <span class="tok-punc">=></span> <span class="tok-var">console</span><span class="tok-punc">.</span><span class="tok-fn">log</span><span class="tok-punc">(</span><span class="tok-var">err</span><span class="tok-punc">.</span><span class="tok-var">errors</span><span class="tok-punc">));</span></div>
<div class="pa2-toggle-row">
<span class="pa2-toggle-label">all three reject?</span>
<div class="pa2-toggle" id="anyToggle">
<button class="off is-active" data-val="off" type="button">no</button>
<button class="on" data-val="on" type="button">yes</button>
</div>
</div>
<div class="pa2-tasks">
<div class="pa2-task" id="anyT1"><div class="pa2-task-label">p1</div><div class="pa2-task-track"><div class="pa2-task-bar"></div></div><div class="pa2-task-mark chk">✓</div><div class="pa2-task-mark crs">✕</div></div>
<div class="pa2-task" id="anyT2"><div class="pa2-task-label">p2</div><div class="pa2-task-track"><div class="pa2-task-bar"></div></div><div class="pa2-task-mark chk">✓</div><div class="pa2-task-mark crs">✕</div></div>
<div class="pa2-task" id="anyT3"><div class="pa2-task-label">p3</div><div class="pa2-task-track"><div class="pa2-task-bar"></div></div><div class="pa2-task-mark chk">✓</div><div class="pa2-task-mark crs">✕</div></div>
</div>
<div class="pa2-result" id="anyResult"><div class="pa2-rname">Promise.any</div><div class="pa2-rval" id="anyResultVal"></div></div>
<button class="pa2-play" data-run="any" type="button">run</button>
</div>
</div>
</div>
<script>
(function () {
const wrapper = document.currentScript.closest('.infographic-promiseapis')
|| document.querySelector('.infographic-promiseapis');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') { dark = true; }
else if (bodyAttr === 'false') { dark = false; }
else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
/* tabs */
wrapper.querySelectorAll('.pa2-tab').forEach(tab => {
tab.addEventListener('click', () => {
wrapper.querySelectorAll('.pa2-tab').forEach(t => t.classList.remove('is-active'));
wrapper.querySelectorAll('.pa2-panel').forEach(p => p.classList.remove('is-active'));
tab.classList.add('is-active');
wrapper.querySelector('.pa2-panel[data-panel="' + tab.dataset.tab + '"]').classList.add('is-active');
});
});
/* toggles */
function wireToggle(id, onChange) {
const el = wrapper.querySelector('#' + id);
let val = 'off';
el.querySelectorAll('button').forEach(b => {
b.addEventListener('click', () => {
val = b.dataset.val;
el.querySelectorAll('button').forEach(x => x.classList.remove('is-active'));
b.classList.add('is-active');
onChange(val);
});
});
return () => val;
}
let allFails = false;
wireToggle('allToggle', v => { allFails = v === 'on'; });
let raceFails = false;
wireToggle('raceToggle', v => { raceFails = v === 'on'; });
let anyAllFail = false;
wireToggle('anyToggle', v => { anyAllFail = v === 'on'; });
function growBar(track, ms) {
const bar = track.querySelector('.pa2-task-bar');
bar.style.transition = 'none';
bar.style.width = '0%';
void bar.offsetWidth;
bar.style.transition = 'width ' + ms + 'ms linear';
requestAnimationFrame(() => { bar.style.width = '100%'; });
}
function resetTask(el) {
el.classList.remove('good', 'bad', 'dim');
}
/* resolve / reject pipeline */
function runPipeline(prefix, finalClass, badgeText) {
const step1 = wrapper.querySelector('#' + prefix + 'Step1');
const step2 = wrapper.querySelector('#' + prefix + 'Step2');
const step3 = wrapper.querySelector('#' + prefix + 'Step3');
const conn1 = wrapper.querySelector('#' + prefix + 'Conn1 .pa2-pconnect-fill');
const conn2 = wrapper.querySelector('#' + prefix + 'Conn2 .pa2-pconnect-fill');
const card = wrapper.querySelector('#' + prefix + 'Card');
const badge = wrapper.querySelector('#' + prefix + 'Badge');
[step1, step2, step3].forEach(s => s.classList.remove('is-active', 'is-processing', 'is-good', 'is-bad'));
conn1.style.width = '0%';
conn2.style.width = '0%';
card.classList.remove('good', 'bad');
badge.textContent = 'idle';
setTimeout(() => { step1.classList.add('is-active'); }, 60);
setTimeout(() => { conn1.style.width = '100%'; }, 260);
setTimeout(() => { step1.classList.remove('is-active'); step2.classList.add('is-active', 'is-processing'); }, 420);
setTimeout(() => { conn2.style.width = '100%'; }, 900);
setTimeout(() => {
step2.classList.remove('is-active', 'is-processing');
step3.classList.add(finalClass);
card.classList.add(finalClass === 'is-good' ? 'good' : 'bad');
badge.textContent = badgeText;
}, 1050);
}
wrapper.querySelector('[data-run="resolve"]').addEventListener('click', () => {
runPipeline('rs', 'is-good', 'fulfilled → "Success!"');
});
wrapper.querySelector('[data-run="reject"]').addEventListener('click', () => {
runPipeline('rj', 'is-bad', 'rejected → "Something went wrong!"');
});
/* all */
wrapper.querySelector('[data-run="all"]').addEventListener('click', function () {
const btn = this;
btn.disabled = true;
const t1 = wrapper.querySelector('#allT1'), t2 = wrapper.querySelector('#allT2'), t3 = wrapper.querySelector('#allT3');
const result = wrapper.querySelector('#allResult'), rval = wrapper.querySelector('#allResultVal');
[t1, t2, t3].forEach(resetTask);
result.classList.remove('good', 'bad'); rval.classList.remove('is-shown'); rval.textContent = '';
growBar(t1.querySelector('.pa2-task-track'), 600);
growBar(t3.querySelector('.pa2-task-track'), 900);
growBar(t2.querySelector('.pa2-task-track'), allFails ? 750 : 1200);
setTimeout(() => t1.classList.add('good'), 600);
if (allFails) {
setTimeout(() => { t2.classList.add('bad'); }, 750);
setTimeout(() => {
result.classList.add('bad');
rval.textContent = 'Error: Failed';
rval.classList.add('is-shown');
t3.classList.add('dim');
btn.disabled = false;
}, 850);
} else {
setTimeout(() => t3.classList.add('good'), 900);
setTimeout(() => t2.classList.add('good'), 1200);
setTimeout(() => {
result.classList.add('good');
rval.textContent = '[10, 20, 30]';
rval.classList.add('is-shown');
btn.disabled = false;
}, 1350);
}
});
/* allSettled */
wrapper.querySelector('[data-run="allsettled"]').addEventListener('click', function () {
const btn = this;
btn.disabled = true;
const t1 = wrapper.querySelector('#asT1'), t2 = wrapper.querySelector('#asT2'), t3 = wrapper.querySelector('#asT3');
const result = wrapper.querySelector('#asResult'), rval = wrapper.querySelector('#asResultVal');
[t1, t2, t3].forEach(resetTask);
result.classList.remove('good'); rval.classList.remove('is-shown'); rval.textContent = '';
growBar(t1.querySelector('.pa2-task-track'), 600);
growBar(t2.querySelector('.pa2-task-track'), 900);
growBar(t3.querySelector('.pa2-task-track'), 1300);
setTimeout(() => t1.classList.add('good'), 600);
setTimeout(() => t2.classList.add('bad'), 900);
setTimeout(() => t3.classList.add('good'), 1300);
setTimeout(() => {
result.classList.add('good');
rval.textContent = "[ {fulfilled,'OK'}, {rejected,'Error occured'}, {fulfilled,'Done'} ]";
rval.classList.add('is-shown');
btn.disabled = false;
}, 1450);
});
/* race */
wrapper.querySelector('[data-run="race"]').addEventListener('click', function () {
const btn = this;
btn.disabled = true;
const t1 = wrapper.querySelector('#raceT1'), t2 = wrapper.querySelector('#raceT2');
const result = wrapper.querySelector('#raceResult'), rval = wrapper.querySelector('#raceResultVal');
[t1, t2].forEach(resetTask);
result.classList.remove('good', 'bad'); rval.classList.remove('is-shown'); rval.textContent = '';
growBar(t1.querySelector('.pa2-task-track'), 400);
growBar(t2.querySelector('.pa2-task-track'), 1100);
setTimeout(() => {
if (raceFails) { t1.classList.add('bad'); } else { t1.classList.add('good'); }
}, 400);
setTimeout(() => {
if (raceFails) {
result.classList.add('bad');
rval.textContent = '"Failed first"';
} else {
result.classList.add('good');
rval.textContent = '"Fast!"';
}
rval.classList.add('is-shown');
t2.classList.add('dim');
}, 500);
setTimeout(() => { t2.classList.add('good'); btn.disabled = false; }, 1100);
});
/* any */
wrapper.querySelector('[data-run="any"]').addEventListener('click', function () {
const btn = this;
btn.disabled = true;
const t1 = wrapper.querySelector('#anyT1'), t2 = wrapper.querySelector('#anyT2'), t3 = wrapper.querySelector('#anyT3');
const result = wrapper.querySelector('#anyResult'), rval = wrapper.querySelector('#anyResultVal');
[t1, t2, t3].forEach(resetTask);
result.classList.remove('good', 'bad'); rval.classList.remove('is-shown'); rval.textContent = '';
growBar(t1.querySelector('.pa2-task-track'), 400);
growBar(t2.querySelector('.pa2-task-track'), 800);
growBar(t3.querySelector('.pa2-task-track'), 1200);
setTimeout(() => { t1.classList.add('bad'); }, 400);
if (anyAllFail) {
setTimeout(() => t2.classList.add('bad'), 800);
setTimeout(() => t3.classList.add('bad'), 1200);
setTimeout(() => {
result.classList.add('bad');
rval.textContent = '["Err 1", "Err 2", "Err 3"]';
rval.classList.add('is-shown');
btn.disabled = false;
}, 1350);
} else {
setTimeout(() => {
t2.classList.add('good');
result.classList.add('good');
rval.textContent = '"Data loaded!"';
rval.classList.add('is-shown');
t3.classList.add('dim');
}, 800);
setTimeout(() => { t3.classList.add('good'); btn.disabled = false; }, 1200);
}
});
})();
</script>