completefrontend
Open lab My progress
THE JAVASCRIPT FIELD GUIDE

Promise combinators

Learn how JavaScript combines many promises with Promise.all, allSettled, race, any, withResolvers, Promise.try, and the proposed keyed helpers.

By the end, you'll know which method to pick
  • 01
    Wait the right wayUse all, allSettled, race, and any when you need every value, a report for each promise, the first result, or the first success.
  • 02
    Predict the small casesSay what happens with an empty array, a plain value, a failure in Promise.all, and an AggregateError. Know that values come back in input order.
  • 03
    Use the newer methods safelyCheck that withResolvers, Promise.try, and the proposed allKeyed exist before you use them, and use a fallback when they don't.

Many promises, one plan

A promise is an object that stands for a result that isn't ready yet. You met it in the Promises lesson. Real pages often wait for many things at once:

  • A dashboard may need the user, the settings, the messages, and the chart data.
  • A photo uploader may send ten photos at the same time.
  • A page may ask three servers for the same file and keep the first good answer.

Each promise ends in one of two ways. It fulfills: the work worked, and the promise has a value. Or it rejects: the work failed, and the promise has a reason. Both are called settling. A promise that hasn't settled yet is pending.

Promise combinators are methods that turn many promises into one promise. You call them on Promise itself, like Promise.all(...). You give them a list of promises, usually an array. They give back one new promise for the whole group. This lesson also uses ideas from Microtasks in depth, Promise chaining, and Error handling with promises.

The short version

Each method answers a different question about the group:

  • Promise.all: did every promise succeed? Give me all the values.
  • Promise.allSettled: how did each promise end? Give me a report for each one.
  • Promise.race: which promise finished first, success or failure?
  • Promise.any: which promise succeeded first?
One result from two promisesPop out in the code editor (opens in a new tab)JavaScript
const user = Promise.resolve("Asha");const cartItems = Promise.resolve(3); Promise.all([user, cartItems]).then((values) => {  console.log(values.join(" / "));});

Line 1 makes a promise that fulfills with the name "Asha". Line 2 makes a promise that fulfills with the number 3, the number of items in a cart. Line 4 gives both promises to Promise.all in an array. When both are done, values is the array ["Asha", 3]. Line 5 joins the values and prints Asha / 3.

Real-life analogyPromise.all is a group dinner

Four friends order dinner together. The waiter serves the table only when every dish is ready. If the kitchen drops one dish, the waiter comes back right away with the bad news. The soup and the dessert are still cooking in the kitchen.

In real life: Every dish reaches the table
In JavaScript: Every input fulfills, so Promise.all fulfills
In real life: Each plate goes to the person who ordered it
In JavaScript: The values come back in the order you passed the promises in
In real life: The kitchen drops one dish
In JavaScript: The group promise rejects with the reason from the first failure
In real life: The other dishes keep cooking
In JavaScript: The other promises keep running; nothing is stopped

Each method in this lesson answers one question. Do you need every value, a report for each one, the first result, or the first success?

Promise.all & allSettled

INTERACTIVE

Promise.all takes an iterable: anything you can loop over with for...of, like an array. Each item can be:

  • a promise,
  • a thenable: any object with a then method, which JavaScript treats like a promise,
  • or a plain value, like "plain". A plain value counts as a promise that has already fulfilled.

If the array is empty, Promise.all([]) fulfills right away with an empty array.

The values come back in input order: the order you passed the promises in. They don't come back in the order the promises finish. So a slow promise placed first still gets the first place.

Three promises passed in as A, B, C. A finishes third, B finishes first, C finishes second. An arrow leads to a cart called values that holds A, B, C in that same order. The output is A ready | B ready | C ready.you pass inAfinishes 3rdBfinishes 1stCfinishes 2ndyou get backABCvaluesA ready | B ready | C ready
In the replay below, B finishes first and A finishes last. Promise.all still lists the values in the order you passed them in: A, B, C.

The replay below uses three cooking tasks. Each task is a promise with a timer:

  • Task A takes 30 milliseconds.
  • Task B takes 10 milliseconds.
  • Task C takes 20 milliseconds.

Choose which task fails, then step through it. When one task fails, Promise.all rejects right away. This is called fail-fast. The other tasks are not stopped. Their timers still run to the end.

Promise.all stops waiting, but the tasks keep running
Step 0 of 9Ready
Your turn: follow the blue line

Choose which task fails. Predict whether Promise.all prints all three values or one failure.

Running in
  1. script
Next: line 11
function cook(label, ms, shouldFail) {  return new Promise((resolve, reject) => {    setTimeout(() => {      if (shouldFail) reject(label + " dropped");      else resolve(label + " ready");    }, ms);  });} const orders = [  cook("B", 10, true),  cook("C", 20, false),]; Promise.all(orders).then(  (values) => console.log(values.join(" | ")),  (reason) => console.log("failed: " + reason),);
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
Which task fails?
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Promise.allSettled also takes an iterable. It waits until every promise has settled, even the ones that fail. A failed input doesn't make it reject. It gives back one report object for each input:

  • For a promise that fulfilled: { status: "fulfilled", value }.
  • For a promise that rejected: { status: "rejected", reason }.

Use it when you want to show every result, failures included. Upload reports and test results are good examples.

Get a report for each promisePop out in the code editor (opens in a new tab)JavaScript
Promise.allSettled([  Promise.resolve("saved"),  Promise.reject("offline"),]).then((results) => {  console.log(results.map((item) => item.status).join(" / "));});

Line 2 is a promise that fulfills with "saved". Line 3 is a promise that rejects with "offline". results holds two report objects, in input order. Line 5 reads the status of each report and prints fulfilled / rejected. The failed promise is still in the report.

Left: Promise.all gets saved and offline. Offline rejects, so Promise.all rejects with offline. Right: Promise.allSettled gets the same two inputs and fulfills with two reports, fulfilled and rejected.Promise.allsavedofflineofflinerejectsPromise.allSettledsavedofflinefulfilledrejectedfulfills
Same two inputs on both sides. Promise.all stops at the first failure. Promise.allSettled waits for both and gives you one report for each.
Real-life analogyallSettled is a teacher collecting every exam

A teacher doesn't stop collecting exams because one student failed. The class report is only useful once every paper is in. allSettled works the same way: it doesn't stop early, and no row is missing.

In real life: Every exam paper is handed in
In JavaScript: Every input settles before the group promise fulfills
In real life: Some students pass, some fail
In JavaScript: Each report has the status fulfilled or rejected
In real life: The teacher reads out the full class report
In JavaScript: You get an array of report objects

In the kitchen race track below, four tasks run on real timers. Pick a method to run them with and watch the timeline. You'll meet race and any in the next section.

Kitchen race track
Four kitchen tasksPop out in the code editor (opens in a new tab)JavaScript
const tasks = [  task("A", 800, true),  task("B", 450, true),  task("C", 1100, false),]; Promise.all(tasks);        // every task must fulfillPromise.allSettled(tasks); // report every resultPromise.race(tasks);       // first to finish winsPromise.any(tasks);        // first success wins
Timelineall
Task A
Task B
Task C
Task D

Press a Run button to start the tasks.

  1. Nothing has finished yet.
Try it yourself

Promise.all waits for every task to succeed. It rejects as soon as one task fails. Watch the other timers: they still finish.

The tasks are real promises with real timers, running in your browser. The star (★) row is the group promise. Reset stops the timers and puts the tasks back.

Promise.race & Promise.any

SORT IT

Promise.race settles as soon as the first input settles. It copies that first result:

  • If the first promise to finish fulfills, the race fulfills with its value.
  • If the first promise to finish rejects, the race rejects with its reason.

With an empty array, Promise.race([]) stays pending forever. There is no promise that can finish first.

Promise.any waits for the first promise that fulfills. It skips failures, as long as another promise could still succeed. If every input rejects, Promise.any rejects with an AggregateError. An AggregateError is one error that holds a list of errors. Its .errors array lists the reasons in input order. Promise.any([]) rejects right away with an AggregateError, because no promise can ever succeed.

race can fail while any succeedsPop out in the code editor (opens in a new tab)JavaScript
const offline = Promise.reject("offline");const tea = Promise.resolve("tea"); Promise.race([offline, tea]).catch((reason) => console.log("race: " + reason));Promise.any([offline, tea]).then((value) => console.log("any: " + value));

Line 1 is a promise that has already rejected with "offline". Line 2 is a promise that has already fulfilled with "tea". Both lines 4 and 5 get the same array:

  • Line 4: race takes the first result, which is the failure. It prints race: offline.
  • Line 5: any skips the failure and takes the success. It prints any: tea.
A cart called inputs holds offline, which is rejected, and tea, which is fulfilled. One arrow goes to race, which prints race: offline. Another arrow goes to any, which prints any: tea.rejectedfulfilledofflineteainputsracerace: offlineanyany: tea
The same two inputs go to both methods. race takes the first one to finish, even a failure. any skips the failure and takes the first success.
Real-life analogyrace is a horse race; any is job applications

In a horse race, the first thing that happens makes the news. A horse wins, or the favorite falls. When you apply for jobs, one yes is enough. You give up only when every company says no.

In real life: The first horse crosses the line, or falls
In JavaScript: Promise.race uses the first result, success or failure
In real life: One job offer is enough
In JavaScript: Promise.any fulfills with the first success
In real life: Every company says no
In JavaScript: Promise.any rejects with an AggregateError
Which method fits?
  • Load the profile, permissions, and settings before you show a dashboard
  • Upload 8 photos and show which ones worked and which failed
  • Race a timer so you stop waiting after 3 seconds
  • Ask three copies of a server and use the first good answer
  • Collect every exam result before you read out the class report
  • Show whichever connection try finishes first, success or failure
  • Wait for soup, salad, and dessert before you serve a table
  • Send job applications and celebrate the first yes
Try it yourself
0 of 8 correct

Put each real task under the method that fits it best.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Here are the small cases that are easy to forget. The last line rejects on purpose.

Small cases worth rememberingPop out in the code editor (opens in a new tab)JavaScript
await Promise.all(["plain", Promise.resolve("promise")]);await Promise.all([]);Promise.race([]); // stays pending foreverawait Promise.any([]); // rejects with AggregateError
  • Line 1: a plain value and a promise in one array. You get ["plain", "promise"].
  • Line 2: an empty array. You get an empty array.
  • Line 3: an empty race never settles, so the code doesn't wait for it.
  • Line 4: an empty any rejects with an AggregateError.
Each method treats an empty array its own wayPop out in the code editor (opens in a new tab)JavaScript
Promise.all([]).then((values) => console.log("all " + values.length));Promise.allSettled([]).then((values) => console.log("settled " + values.length));Promise.any([]).catch((error) => console.log(error.name + " " + error.errors.length)); let raceSettled = false;Promise.race([]).then(() => { raceSettled = true; });setTimeout(() => console.log("race pending " + !raceSettled), 10);

Lines 1 to 3 give each method an empty array. Line 5 starts an empty race, and line 6 checks it 10 milliseconds later. The output is:

  • all 0: Promise.all fulfilled with an empty array.
  • settled 0: Promise.allSettled did the same.
  • AggregateError 0: Promise.any rejected with an AggregateError that holds no errors.
  • race pending true: the race is still pending.

So if your array might be empty, don't pass it to Promise.race alone. Add a timer or another way to stop waiting.

Promise.withResolvers

NEWER API

Usually you make a promise with new Promise((resolve, reject) => ...). The two functions resolve and reject settle the promise. But they only exist inside those brackets.

Sometimes the code that makes the promise isn't the code that knows when to settle it. A click handler is one example. Promise.withResolvers() helps here. It gives back an object with three things:

  • promise: the new promise, which other code can wait on.
  • resolve: a function that fulfills the promise.
  • reject: a function that rejects the promise.

It works in current browsers and in Node 22. If your code must also run on older versions, check that it exists first. This check is called feature detection.

Real-life analogyThe counter holds the buttons

At a coffee shop you get an order number. The person at the counter has two buttons: one marks your order ready, and one marks it sold out. You wait; they press a button when they know.

In real life: You hold an order number
In JavaScript: The promise that someone can wait on
In real life: The counter marks your order ready
In JavaScript: The resolve function
In real life: The counter marks your order sold out
In JavaScript: The reject function
Settle a promise from outsidePop out in the code editor (opens in a new tab)JavaScript
const { promise, resolve } = Promise.withResolvers();resolve("order ready"); promise.then((value) => console.log(value));

Line 1 makes the promise and takes out promise and resolve. Line 2 calls resolve with the value "order ready". No new Promise brackets are needed. Line 4 adds a handler. The handler runs a moment later and prints order ready.

A function card, withResolvers(), gives back an object. The object holds two things: the promise, which you wait on, and resolve, which settles it. Calling resolve makes the promise fulfill, and the handler prints order ready.withResolvers()wait on itsettle itpromiseresolveobjectorder readyline 4 prints
One call gives you the promise and the resolve function that settles it. Line 2 calls resolve, so line 4 prints order ready.
Settle a promise from outside
waitForClick, built with withResolversPop out in the code editor (opens in a new tab)JavaScript
function waitForClick(button) {  const { promise, resolve, reject } = Promise.withResolvers();   button.addEventListener("click", () => {    resolve("button clicked");  }, { once: true });   return { promise, cancel: () => reject("cancelled") };}
Promise stateidle

checking…

  1. Make a promise, then settle it with the buttons.
Try it yourself

withResolvers makes the promise in one place. Other code can settle it later.

Promise.withResolvers works in current browsers and in Node 22. For older versions, the lesson uses a fallback.

A real use is waitForClick(button). It makes a promise and fulfills it when the button is clicked. It can also hand out a cancel function that rejects the promise.

Promise.try

FEATURE DETECT

A function can fail in two ways:

  • It can throw an error right away. This is a synchronous throw: it happens now, before the function returns.
  • It can return a promise that rejects later.

Promise.try(fn) handles both the same way. It calls fn right now and gives back a promise for its result. If fn throws right away, that promise rejects. So one .catch handles both kinds of failure.

Promise.try is new. It works in newer browsers and in Node 23, but not in Node 22. So this lesson checks whether it exists. If it doesn't, the lesson uses a small stand-in function instead. A stand-in like this is called a fallback.

Real-life analogyPromise.try is a safety net

A tightrope walker can fall at the first step or halfway across. Without a net, you need one plan for each kind of fall. With one net under the whole rope, both falls land in the same place.

In real life: You trip as soon as you step onto the rope
In JavaScript: fn throws right away
In real life: You slip halfway across the rope
In JavaScript: fn returns a promise that rejects later
In real life: The same net catches both falls
In JavaScript: One .catch handles either failure
Promise.try safety net
Promise.try with a fallbackPop out in the code editor (opens in a new tab)JavaScript
function promiseTry(fn, ...args) {  if (typeof Promise.try === "function") {    return Promise.try(fn, ...args);  }  return new Promise((resolve) => resolve(fn(...args)));} promiseTry(readConfig)  .then((value) => console.log(value))  .catch((error) => console.log(error.message));
Run logthrow
  1. Choose what the function does, then press Run.
Try it yourself

Promise.try calls the function right away. If the function throws right away, Promise.try turns that into a rejected promise. So one catch handles both kinds of failure. Promise.resolve().then(fn) would call fn a moment later instead.

Promise.try works in newer browsers and in Node 23, but not in Node 22. So the lesson's tests use the fallback.

You may also see Promise.resolve().then(fn). It also turns a throw into a rejection. But it doesn't call fn right away. It calls it a moment later, as a microtask: a small job that runs after the current code finishes. Promise.try(fn) calls fn right away.

Promise.try calls the function nowPop out in the code editor (opens in a new tab)JavaScript
function promiseTry(fn) {  if (typeof Promise.try === "function") return Promise.try(fn);  return new Promise((resolve) => resolve(fn()));} function readPrice() {  console.log("read now");  return 3;} promiseTry(readPrice).then((price) => console.log("price " + price));console.log("after call");

Lines 1 to 4 are the fallback helper. Line 2 uses the real Promise.try if it exists. Line 3 is the fallback: it calls fn inside new Promise, which also turns a throw into a rejection.

Line 11 calls readPrice through the helper. The output is:

  1. read now: readPrice runs right away, from line 7.
  2. after call: line 12 runs next.
  3. price 3: the .then handler runs last, after the current code finishes.

Promises in an object: Promise.allKeyed

PROPOSAL

Promise.all gives back an array. When each place in the array means something different, it's easy to mix them up. Look at this code:

The names are in the wrong orderPop out in the code editor (opens in a new tab)JavaScript
const [alerts, user] = await Promise.all([  fetchUser(),  fetchAlerts(),]);// Oops: alerts contains the user, and user contains the alerts.

Line 1 takes the two values out of the array by place. The first value goes into alerts, and the second goes into user. But line 2 puts fetchUser() first. So the names are swapped.

A new feature fixes this. It adds two methods, Promise.allKeyed and Promise.allSettledKeyed. You give them an object of promises, and they give back an object with the same property names. Then you read result.user, not the first place in an array.

This feature is a proposal: a planned addition that isn't part of the language yet. Firefox 155 has early, experimental support. Node 22 and most browsers don't have it.

Real-life analogyallKeyed is a labeled lunchbox

A lunchbox with labeled parts is hard to mix up. A row of plain bowls that all look the same is easy to mix up. Keyed methods keep the names next to the results.

In real life: Each part of the lunchbox has a label
In JavaScript: Each property name stays with its value
In real life: The rice and the fruit can't swap places
In JavaScript: You read result.user, not the first place in an array
In real life: A broken part still has its label
In JavaScript: allSettledKeyed gives a report under each name
Labeled lunchbox: allKeyed helper
allKeyed helperPop out in the code editor (opens in a new tab)JavaScript
async function allKeyed(object) {  const keys = Object.keys(object);  const values = await Promise.all(keys.map((key) => object[key]));  return Object.fromEntries(keys.map((key, index) => [key, values[index]]));} const dashboard = await allKeyed({  user: fetchUser(),  stats: fetchStats(),  alerts: fetchAlerts(),});
allSettledKeyed helperPop out in the code editor (opens in a new tab)JavaScript
async function allSettledKeyed(object) {  const keys = Object.keys(object);  const results = await Promise.allSettled(keys.map((key) => object[key]));  return Object.fromEntries(keys.map((key, index) => [key, results[index]]));}
Keyed resultsuccess

checking…

  1. Run a helper. The names stay next to their values.
Try it yourself

allKeyed waits for an object of promises and keeps each property name next to its value. If alerts fails, allKeyed rejects, but allSettledKeyed still gives a report under each name.

The planned feature also handles symbol keys. These helpers use Object.keys, which lists only text names, to keep the code short.

You can write a small version yourself today:

A small allKeyed helperPop out in the code editor (opens in a new tab)JavaScript
async function allKeyed(object) {  const keys = Object.keys(object);  const values = await Promise.all(keys.map((key) => object[key]));  return Object.fromEntries(keys.map((key, index) => [key, values[index]]));} const dashboard = await allKeyed({  user: fetchUser(),  stats: fetchStats(),  alerts: fetchAlerts(),});
  1. Line 1 defines the helper. It takes an object of promises.
  2. Line 2 saves the property names, like ["user", "stats", "alerts"].
  3. Line 3 waits for all the values with Promise.all. They come back in the same order as the names.
  4. Line 4 puts each name back next to its value and builds a new object.

The helper uses Object.keys, which lists only the text property names. The real feature also handles symbol keys. For most code, text names are all you need.

Where you'll use combinators

The method you pick tells the reader what your code needs:

  • Promise.all says: "This page needs every piece."
  • Promise.allSettled says: "Show how each one ended."
  • Promise.any says: "The first success is enough."
  • Promise.race says: "Whatever finishes first decides."
Load a dashboardPop out in the code editor (opens in a new tab)JavaScript
async function loadDashboard() {  const [user, widgets, flags] = await Promise.all([    loadUser(),    loadWidgets(),    loadFeatureFlags(),  ]);   const uploads = await Promise.allSettled(files.map(uploadFile));  const fastest = await Promise.any(cdnMirrors.map(loadFromMirror));   return { user, widgets, flags, uploads, fastest };}
  • Line 2 needs the user, the widgets, and the feature flags. If one fails, the dashboard can't show.
  • Line 8 uploads every file and keeps a report for each one, failed or not.
  • Line 9 asks several copies of the same server and takes the first one that answers well.
A timeout race is only the first step

A common trick is to race the real work against a timer. If the timer finishes first, you stop waiting. But the slow request is not stopped; it keeps running. Real code usually adds AbortController, a tool that can stop a request. The Async patterns lesson shows the full version.

Race the work against a timerPop out in the code editor (opens in a new tab)JavaScript
const timeout = new Promise((_, reject) => {  setTimeout(() => reject(new Error("too slow")), 3000);}); const data = await Promise.race([loadData(), timeout]);

Line 1 makes a promise that rejects with "too slow" after 3000 milliseconds, which is 3 seconds. Line 5 races loadData() against it. If the data comes first, data gets it. If the timer comes first, the await throws the "too slow" error.

Common misconceptions

Read each row from left to right: the method, when it fulfills, when it rejects, and what it's good for.

The four methods side by side
MethodWhen does it fulfill?When does it reject?What is it good for?
Promise.allEvery input fulfills. The values are in input order.The first input rejects.Data the page can't work without.
Promise.allSettledEvery input settles. You get a report for each one.Never because an input failed.Reports that show every result.
Promise.raceThe first input to settle fulfills.The first input to settle rejects.Stopping a wait with a timer.
Promise.anyThe first input fulfills.Every input rejects. You get an AggregateError.Backups, where one success is enough.
  • "Promise.all stops the other promises." It doesn't. It rejects early, but the other work keeps running unless you stop it yourself.
  • "The values come back in the order they finish." No. all and allSettled keep input order.
  • "allSettled gives me the values." It gives report objects. Check status first, then read value or reason.
  • "race means the first success." race means the first result, success or failure. Use any for the first success.
  • "New methods work everywhere." Check that withResolvers, Promise.try, and proposals like allKeyed exist before you use them.

Practice exercises

5 EXERCISES
Exercise 1 · Warm-upPredict the order from Promise.all

Run the code in your head. What one line does it print?

Starter codePop out in the code editor (opens in a new tab)JavaScript
const slow = new Promise((resolve) => setTimeout(() => resolve("slow"), 20));
const fast = Promise.resolve("fast");
Promise.all([slow, fast, "plain"]).then((values) => console.log(values.join(",")));

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeThe first success wins

    Which value reaches the then handler?

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    Promise.any([
      Promise.reject("no A"),
      new Promise((resolve) => setTimeout(() => resolve("yes B"), 5)),
      Promise.resolve("yes C"),
    ]).then((value) => console.log(value));

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeReport every upload

      What status text does it print?

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      Promise.allSettled([Promise.resolve("ok"), Promise.reject("bad")])
        .then((results) => console.log(results.map((item) => item.status).join("/")));

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · ChallengeWrite a helper that keeps the names

        Read the helper, then predict what it prints.

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        async function allKeyed(object) {
          const keys = Object.keys(object);
          const values = await Promise.all(keys.map((key) => object[key]));
          return Object.fromEntries(keys.map((key, index) => [key, values[index]]));
        }
        allKeyed({ user: Promise.resolve("Ada"), count: 3 })
          .then((result) => console.log(result.user + " " + result.count));

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeCatch a throw as a rejection

          What does the .catch print?

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          function promiseTry(fn) {
            if (typeof Promise.try === "function") return Promise.try(fn);
            return new Promise((resolve) => resolve(fn()));
          }
          promiseTry(() => { throw new Error("sync boom"); })
            .catch((error) => console.log(error.message));

          Answer, then press Check. Spacing and letter case don’t matter.

            Check your understanding

            8 QUESTIONS
            Promise combinators quiz · 8 questionsScore: first tries count
            1. Question 1 of 8What does Promise.all do when one input rejects?

              Choose an answer to see the explanation.

            2. Question 2 of 8What does this print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              Promise.all([Promise.resolve("A"), "B"])
                .then((values) => console.log(values.join("-")));

              Choose an answer to see the explanation.

            3. Question 3 of 8Which method never rejects because one input failed?

              Choose an answer to see the explanation.

            4. Question 4 of 8What happens with Promise.race([])?

              Choose an answer to see the explanation.

            5. Question 5 of 8What does Promise.any reject with when every input rejects?

              Choose an answer to see the explanation.

            6. Question 6 of 8What is Promise.withResolvers useful for?

              Choose an answer to see the explanation.

            7. Question 7 of 8Why does this lesson check that Promise.try exists before using it?

              Choose an answer to see the explanation.

            8. Question 8 of 8What is true about the allKeyed proposal?

              Choose an answer to see the explanation.

            Key takeaways

            • Promise.all is for "every one must succeed." It keeps input order. It rejects with the reason from the first failure.
            • Promise.allSettled is for reports. It waits for every input and gives a report object for each one.
            • Promise.race takes the first result, success or failure. Promise.any takes the first success, or rejects with an AggregateError.
            • withResolvers and Promise.try are newer. Check that they exist, and use a fallback when they don't.
            • allKeyed is a proposal. A small helper built on Object.keys gives you the same idea today.

            Final definition: A promise combinator turns many promises into one promise. You pick the one whose waiting rule matches what your code needs.

            Up next: Promisification & promise-based APIs.

            CompleteFrontend Clear concepts. Working examples.