Promise all catch error

The Promise.all() static method takes an iterable of promises as input and returns a single Promise. This returned promise fulfills when all of the input's promises fulfill (including when an empty iterable is passed), with an array of the fulfillment values. It rejects when any of the input's promises rejects, with this first rejection reason.

The Promise.all() static method takes an iterable of promises as input and returns a single Promise. This returned promise fulfills when all of the input’s promises fulfill (including when an empty iterable is passed), with an array of the fulfillment values. It rejects when any of the input’s promises rejects, with this first rejection reason.

Try it

Syntax

Parameters

iterable

An iterable (such as an Array) of promises.

Return value

A Promise that is:

  • Already fulfilled, if the iterable passed is empty.
  • Asynchronously fulfilled, when all the promises in the given iterable fulfill. The fulfillment value is an array of fulfillment values, in the order of the promises passed, regardless of completion order. If the iterable passed is non-empty but contains no pending promises, the returned promise is still asynchronously (instead of synchronously) fulfilled.
  • Asynchronously rejected, when any of the promises in the given iterable rejects. The rejection reason is the rejection reason of the first promise that was rejected.

Description

The Promise.all() method is one of the promise concurrency methods. It can be useful for aggregating the results of multiple promises. It is typically used when there are multiple related asynchronous tasks that the overall code relies on to work successfully — all of whom we want to fulfill before the code execution continues.

Promise.all() will reject immediately upon any of the input promises rejecting. In comparison, the promise returned by Promise.allSettled() will wait for all input promises to complete, regardless of whether or not one rejects. Use allSettled() if you need the final result of every promise in the input iterable.

Examples

Using Promise.all()

Promise.all waits for all fulfillments (or the first rejection).

const p1 = Promise.resolve(3);
const p2 = 1337;
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("foo");
  }, 100);
});

Promise.all([p1, p2, p3]).then((values) => {
  console.log(values); // [3, 1337, "foo"]
});

If the iterable contains non-promise values, they will be ignored, but still counted in the returned promise array value (if the promise is fulfilled):

// All values are non-promises, so the returned promise gets fulfilled
const p = Promise.all([1, 2, 3]);
// The only input promise is already fulfilled,
// so the returned promise gets fulfilled
const p2 = Promise.all([1, 2, 3, Promise.resolve(444)]);
// One (and the only) input promise is rejected,
// so the returned promise gets rejected
const p3 = Promise.all([1, 2, 3, Promise.reject(555)]);

// Using setTimeout, we can execute code after the queue is empty
setTimeout(() => {
  console.log(p);
  console.log(p2);
  console.log(p3);
});

// Logs:
// Promise { <state>: "fulfilled", <value>: Array[3] }
// Promise { <state>: "fulfilled", <value>: Array[4] }
// Promise { <state>: "rejected", <reason>: 555 }

Asynchronicity or synchronicity of Promise.all

This following example demonstrates the asynchronicity of Promise.all when a non-empty iterable is passed:

// Passing an array of promises that are already resolved,
// to trigger Promise.all as soon as possible
const resolvedPromisesArray = [Promise.resolve(33), Promise.resolve(44)];

const p = Promise.all(resolvedPromisesArray);
// Immediately logging the value of p
console.log(p);

// Using setTimeout, we can execute code after the queue is empty
setTimeout(() => {
  console.log("the queue is now empty");
  console.log(p);
});

// Logs, in order:
// Promise { <state>: "pending" }
// the queue is now empty
// Promise { <state>: "fulfilled", <value>: Array[2] }

The same thing happens if Promise.all rejects:

const mixedPromisesArray = [Promise.resolve(33), Promise.reject(44)];
const p = Promise.all(mixedPromisesArray);
console.log(p);
setTimeout(() => {
  console.log("the queue is now empty");
  console.log(p);
});

// Logs:
// Promise { <state>: "pending" }
// the queue is now empty
// Promise { <state>: "rejected", <reason>: 44 }

Promise.all resolves synchronously if and only if the iterable passed is empty:

const p = Promise.all([]); // Will be immediately resolved
const p2 = Promise.all([1337, "hi"]); // Non-promise values are ignored, but the evaluation is done asynchronously
console.log(p);
console.log(p2);
setTimeout(() => {
  console.log("the queue is now empty");
  console.log(p2);
});

// Logs:
// Promise { <state>: "fulfilled", <value>: Array[0] }
// Promise { <state>: "pending" }
// the queue is now empty
// Promise { <state>: "fulfilled", <value>: Array[2] }

Using Promise.all() with async functions

Within async functions, it’s very common to «over-await» your code. For example, given the following functions:

function promptForDishChoice() {
  return new Promise((resolve, reject) => {
    const dialog = document.createElement("dialog");
    dialog.innerHTML = `
<form method="dialog">
  <p>What would you like to eat?</p>
  <select>
    <option value="pizza">Pizza</option>
    <option value="pasta">Pasta</option>
    <option value="salad">Salad</option>
  </select>
  <menu>
    <li><button value="cancel">Cancel</button></li>
    <li><button type="submit" value="ok">OK</button></li>
  </menu>
</form>
    `;
    dialog.addEventListener("close", () => {
      if (dialog.returnValue === "ok") {
        resolve(dialog.querySelector("select").value);
      } else {
        reject(new Error("User cancelled dialog"));
      }
    });
    document.body.appendChild(dialog);
    dialog.showModal();
  });
}

async function fetchPrices() {
  const response = await fetch("/prices");
  return await response.json();
}

You may write a function like this:

async function getPrice() {
  const choice = await promptForDishChoice();
  const prices = await fetchPrices();
  return prices[choice];
}

However, note that the execution of promptForChoice and fetchPrices don’t depend on the result of each other. While the user is choosing their dish, it’s fine for the prices to be fetched in the background, but in the code above, the await operator causes the async function to pause until the choice is made, and then again until the prices are fetched. We can use Promise.all to run them concurrently, so that the user doesn’t have to wait for the prices to be fetched before the result is given:

async function getPrice() {
  const [choice, prices] = await Promise.all([
    promptForDishChoice(),
    fetchPrices(),
  ]);
  return prices[choice];
}

Promise.all is the best choice of concurrency method here, because error handling is intuitive — if any of the promises reject, the result is no longer available, so the whole await expression throws.

Promise.all accepts an iterable of promises, so if you are using it to parallelize execution of several async functions, you need to call the async functions and use the returned promises. Directly passing the functions to Promise.all does not work, since they are not promises.

async function getPrice() {
  const [choice, prices] = await Promise.all([
    promptForDishChoice,
    fetchPrices,
  ]);
  // `choice` and `prices` are still the original async functions;
  // Promise.all() does nothing to non-promises
}

Promise.all fail-fast behavior

Promise.all is rejected if any of the elements are rejected. For example, if you pass in four promises that resolve after a timeout and one promise that rejects immediately, then Promise.all will reject immediately.

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("one"), 1000);
});
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("two"), 2000);
});
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("three"), 3000);
});
const p4 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("four"), 4000);
});
const p5 = new Promise((resolve, reject) => {
  reject(new Error("reject"));
});

// Using .catch:
Promise.all([p1, p2, p3, p4, p5])
  .then((values) => {
    console.log(values);
  })
  .catch((error) => {
    console.error(error.message);
  });

// Logs:
// "reject"

It is possible to change this behavior by handling possible rejections:

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("p1_delayed_resolution"), 1000);
});

const p2 = new Promise((resolve, reject) => {
  reject(new Error("p2_immediate_rejection"));
});

Promise.all([p1.catch((error) => error), p2.catch((error) => error)]).then(
  (values) => {
    console.log(values[0]); // "p1_delayed_resolution"
    console.error(values[1]); // "Error: p2_immediate_rejection"
  },
);

Specifications

Specification
ECMAScript Language Specification
# sec-promise.all

Browser compatibility

BCD tables only load in the browser

See also

All you need to know about Promise.all

Promises in JavaScript are one of the powerful APIs that help us to do Async operations.

Promise.all takes Async operations to the next new level as it helps you to aggregate a group of promises.

In other words, I can say that it helps you to do concurrent operations (sometimes for free).

Prerequisites:

You have to know what is a Promise in JavaScript.

What is Promise.all?

Promise.all is actually a promise that takes an array of promises as an input (an iterable). Then it gets resolved when all the promises get resolved or any one of them gets rejected.

For example, assume that you have ten promises (Async operation to perform a network call or a database connection). You have to know when all the promises get resolved or you have to wait till all the promises resolve. So you are passing all ten promises to Promise.all. Then, Promise.all itself as a promise will get resolved once all the ten promises get resolved or any of the ten promises get rejected with an error.

Let’s see it in code:

Promise.all([Promise1, Promise2, Promise3])
 .then(result) => {
   console.log(result)
 })
 .catch(error => console.log(`Error in promises ${error}`))

As you can see, we are passing an array to Promise.all. And when all three promises get resolved, Promise.all resolves and the output is consoled.

Let’s see an example:

// A simple promise that resolves after a given time
const timeOut = (t) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(`Completed in ${t}`)
    }, t)
  })
}

// Resolving a normal promise.
timeOut(1000)
 .then(result => console.log(result)) // Completed in 1000

// Promise.all
Promise.all([timeOut(1000), timeOut(2000)])
 .then(result => console.log(result)) // ["Completed in 1000", "Completed in 2000"]

In the above example, Promise.all resolves after 2000 ms and the output is consoled as an array.

One interesting thing about Promise.all is that the order of the promises is maintained. The first promise in the array will get resolved to the first element of the output array, the second promise will be a second element in the output array and so on.

Let’s see another example:

// A simple promise that resolves after a given time
const timeOut = (t) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(`Completed in ${t}`)
    }, t)
  })
}

const durations = [1000, 2000, 3000]

const promises = []

durations.map((duration) => {
  // In the below line, two things happen.
  // 1. We are calling the async function (timeout()). So at this point the async function has started and enters the 'pending' state.
  // 2. We are pushing the pending promise to an array.
  promises.push(timeOut(duration)) 
})

console.log(promises) // [ Promise { "pending" }, Promise { "pending" }, Promise { "pending" } ]

// We are passing an array of pending promises to Promise.all
// Promise.all will wait till all the promises get resolves and then the same gets resolved.
Promise.all(promises)
.then(response => console.log(response)) // ["Completed in 1000", "Completed in 2000", "Completed in 3000"]

From the above example, it’s clear that Promise.all waits till all the promises resolve.

Let’s see what happens if any one of the promises are rejected.

// A simple promise that resolves after a given time
const timeOut = (t) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (t === 2000) {
        reject(`Rejected in ${t}`)
      } else {
        resolve(`Completed in ${t}`)
      }
    }, t)
  })
}

const durations = [1000, 2000, 3000]

const promises = []

durations.map((duration) => {
  promises.push(timeOut(duration)) 
})

// We are passing an array of pending promises to Promise.all
Promise.all(promises)
.then(response => console.log(response)) // Promise.all cannot be resolved, as one of the promises passed got rejected.
.catch(error => console.log(`Error in executing ${error}`)) // Promise.all throws an error.

As you can see, if one of the promises fails, then all the rest of the promises fail. Then Promise.all gets rejected.

For some use cases, you don’t need that. You need to execute all the promises even if some have failed, or maybe you can handle the failed promises later.

Let’s see how to handle that.

const durations = [1000, 2000, 3000]

promises = durations.map((duration) => {
  return timeOut(duration).catch(e => e) // Handling the error for each promise.
})

Promise.all(promises)
  .then(response => console.log(response)) // ["Completed in 1000", "Rejected in 2000", "Completed in 3000"]
  .catch(error => console.log(`Error in executing ${error}`))
view raw

Use cases of Promise.all

Assume that you have to perform a huge number of Async operations like sending bulk marketing emails to thousands of users.

Simple pseudo code would be:

for (let i=0;i<50000; i += 1) {
 sendMailForUser(user[i]) // Async operation to send a email
}

The above example is straightforward. But it’s not very performant. The stack will become too heavy and at one point of time, JavaScript will have a huge number of open HTTP connection which may kill the server.

A simple performant approach would be to do it in batches. Take first 500 users, trigger the mail and wait till all the HTTP connections are closed. And then take the next batch to process it and so on.

Let’s see an example:

// Async function to send mail to a list of users.
const sendMailForUsers = async (users) => {
  const usersLength = users.length
  
  for (let i = 0; i < usersLength; i += 100) { 
    const requests = users.slice(i, i + 100).map((user) => { // The batch size is 100. We are processing in a set of 100 users.
      return triggerMailForUser(user) // Async function to send the mail.
       .catch(e => console.log(`Error in sending email for ${user} - ${e}`)) // Catch the error if something goes wrong. So that it won't block the loop.
    })
    
    // requests will have 100 or less pending promises. 
    // Promise.all will wait till all the promises got resolves and then take the next 100.
    await Promise.all(requests)
     .catch(e => console.log(`Error in sending email for the batch ${i} - ${e}`)) // Catch the error.
  }
}


sendMailForUsers(userLists)

Let’s consider another scenario: You have to build an API that gets information from multiple third-party APIs and aggregates all the responses from the APIs.

Promise.all is the perfect way of doing that. Let’s see how.

// Function to fetch Github info of a user.
const fetchGithubInfo = async (url) => {
  console.log(`Fetching ${url}`)
  const githubInfo = await axios(url) // API call to get user info from Github.
  return {
    name: githubInfo.data.name,
    bio: githubInfo.data.bio,
    repos: githubInfo.data.public_repos
  }
}

// Iterates all users and returns their Github info.
const fetchUserInfo = async (names) => {
  const requests = names.map((name) => {
    const url = `https://api.github.com/users/${name}`
    return fetchGithubInfo(url) // Async function that fetches the user info.
     .then((a) => {
      return a // Returns the user info.
      })
  })
  return Promise.all(requests) // Waiting for all the requests to get resolved.
}


fetchUserInfo(['sindresorhus', 'yyx990803', 'gaearon'])
 .then(a => console.log(JSON.stringify(a)))

/*
Output:
[{
  "name": "Sindre Sorhus",
  "bio": "Full-Time Open-Sourcerer ·· Maker ·· Into Swift and Node.js ",
  "repos": 996
}, {
  "name": "Evan You",
  "bio": "Creator of @vuejs, previously @meteor & @google",
  "repos": 151
}, {
  "name": "Dan Abramov",
  "bio": "Working on @reactjs. Co-author of Redux and Create React App. Building tools for humans.",
  "repos": 232
}]
*/

To conclude, Promise.all is the best way to aggregate a group of promises to a single promise. This is one of the ways of achieving concurrency in JavaScript.

Hope you liked this article. If you did, please clap and share it.

Even if you didn’t, that’s fine you can do it anyway :P



Learn to code for free. freeCodeCamp’s open source curriculum has helped more than 40,000 people get jobs as developers. Get started

Последнее обновление: 12.12.2021

Функции Promise.all(), Promise.allSettled() и Promise.race() позволяют сгруппировать выполнение нескольких промисов.

Функция Promise.all

Функция Promise.all() возвращает единый объект Promise, который объединяет набор промисов.

Рассмотрим следуюший код:

const promise1 = new Promise((resolve,reject) => {
	setTimeout(resolve, 1000, "Hello");
});
const promise2 = new Promise((resolve,reject) => {
	setTimeout(resolve, 500, "World");
});
promise1.then(value => console.log(value));	// Hello
promise2.then(value => console.log(value));	// World

Здесь определено два промиса. Асинхронная операция первого промиса выполняется через 1000 миллисекунд, действие второго промиса выполняется через
500 миллисекунд. Оба этих промиса выполняются независимо друг от друга. Консольный вывод:

World
Hello

Функция Promise.all() позволяет объединить несколько промисов и выполнять их параллельно, но как единое целое. В качестве параметра
функция принимает набор промисов:

Promise.all([промис1, промис2, ... прромисN]);

Возвращаемым результатом функции является новый объект Promise.

Теперь изменим предыдущий пример, использовав функцию Promise.all():

const promise1 = new Promise((resolve,reject) => {
	setTimeout(resolve, 1000, "Hello");
});
const promise2 = new Promise((resolve,reject) => {
	setTimeout(resolve, 500, "World");
});
Promise.all([promise1, promise2])
	.then(values => {
				const [promise1data, promise2data] = values;
				console.log(promise1data, promise2data);	// Hello World
});

Теперь данные обоих промисов возвращаются вместе и доступны в методе then() в виде массива values. Консольный вывод:

Hello World

Значения всех промисов возвращаются только если все они завершились успешно. Но если в асинхронной операции хотя бы одного промиса
возникнет ошибка в силу внутренней логики или из-за вызова функции reject(), то все промисы перейдут в состояние rejected, соответственно:

const promise1 = new Promise((resolve,reject) => {
	reject("Непредвиденная ошибка");
	setTimeout(resolve, 500, "Hello");
});
const promise2 = new Promise((resolve,reject) => {
	setTimeout(resolve, 1000, "World");
});

Promise.all([promise1, promise2])
	.then(values => {
				const [promise1data, promise2data] = values;
				console.log(promise1data, promise2data);
})
.catch(error => console.log(error));	// Непредвиденная ошибка

В данном случае мы явным образом переводим переводим первый промис в состояние rejected, соответственно в это состояние переводятся все промисы,
переданные в функцию Promise.all(). И далее через метод catch(), как и в обзем случае, мы можем обработать возникшую ошибку.

Promise.allSettled

Еще одна функция — Promise.allSettled() также как и Promise.all() принимает набор промисов и выполняет их как единое целое, но
возвращает объект со статусом и результатом промиса:

const promise1 = new Promise((resolve,reject) => {
    reject("Непредвиденная ошибка");
    setTimeout(resolve, 500, "Hello");
});
const promise2 = new Promise((resolve,reject) => {
    setTimeout(resolve, 1000, "World");
});
 
Promise.allSettled([promise1, promise2])
    .then(values => {
		const [promise1data, promise2data] = values;
		console.log(promise1data);	// {status: "rejected", reason: "Непредвиденная ошибка"}
		console.log(promise2data);	// {status: "fulfilled", value: "World"}
});

При этом при возникновении ошибки в одном из промисов (как в случае выше с первым промисом) функция также передается результаты в метод then(), который следует дальше в цепочке.
Каждый результат представляет объект. Первое свойство этого объекта — status описывает статус или состояние промиса. Если произошла ошибка, статус rejected, а второе свойство
представляет объект ошибки. Если промис успешно завершил выполнение, то статус fulfilled, а второе свойство — value хранит результат промиса.

Promise.race

Функция Promise.race() также принимает несколько промисов, только возвращает первый завершенный промис (вне зависимости завершился от успешно или с ошибкой):

const promise1 = new Promise((resolve) => {
	setTimeout(resolve, 500, "Hello");
});
const promise2 = new Promise((resolve) => {
	setTimeout(resolve, 1000, "World");
});
Promise.race([promise1, promise2])
	.then(value => console.log(value))		// Hello
	.catch(error => console.log(error));

В данном случае первым выполненным будет промис promise1. Поэтому в метод then(value => console.log(value)) в качестве value
будет передана строка «Hello».

Promise.any

Функция Promise.any() принимает несколько промисов и возвращает первый успешно завершившийся промис:

const promise1 = new Promise((resolve, reject) => {
	reject("error in promise1");
    setTimeout(resolve, 500, "Hello");
});
const promise2 = new Promise((resolve) => {
    setTimeout(resolve, 1000, "World");
});
Promise.any([promise1, promise2])
    .then(value => console.log(value))       // World
    .catch(error => console.log(error));

В данном случае первым выполненным будет промис promise1, однако он завершается с ошибкой. Поэтому в метод then(value => console.log(value)) в качестве value
будет передана строка «World» — результат промиса promise2, который успешно завершается.

Может показаться, что Promise.any() делает то же самое, что и Promise.race(), однако эти функции отличаются в отношении того, как они работают с промисами, которые завершились с ошибкой.
Promise.race() возвращает первый завершенный промис, вне зависимости завершился он с ошибкой или нет. А Promise.any() возвращает первый успешно завершенный промис (если такой имеется).
Если же все промисы завершились с ошибкой, то генерируется исключение типа AggregateError:

const promise1 = new Promise((resolve, reject) => {
	reject("error in promise1");
    setTimeout(resolve, 500, "Hello");
});
const promise2 = new Promise((resolve, reject) => {
	reject("error in promise2");
    setTimeout(resolve, 1000, "World");
});
Promise.any([promise1, promise2])
    .then(value => console.log(value)) 
    .catch(error => console.log(error));	// AggregateError: All promises were rejected

С помощью свойства errors типа AggregateError можно получить в виде массива все ошибки, которые возникли в промисах:

const promise1 = new Promise((resolve, reject) => {
	reject("error in promise1");
    setTimeout(resolve, 500, "Hello");
});
const promise2 = new Promise((resolve, reject) => {
	reject("error in promise2");
    setTimeout(resolve, 1000, "World");
});
Promise.any([promise1, promise2])
    .then(value => console.log(value)) 
    .catch(e => console.log(e.errors));	// ["error in promise1", "error in promise2"]

Понравилась статья? Поделить с друзьями:
  • Prototype 2 mainwin32 error
  • Prototype 2 error could not load prototype2engine dll
  • Proton vpn network error linux
  • Protocol error with rcmd
  • Promag 50 ошибка 321