Tout ce que vous devez savoir sur Promise.all

Les promesses en JavaScript sont l'une des API puissantes qui nous aident à effectuer des opérations Async.

Promise.all élève les opérations Async au niveau supérieur en vous aidant à regrouper un groupe de promesses.

En d'autres termes, je peux dire que cela vous aide à faire des opérations simultanées (parfois gratuitement).

Conditions préalables:

Vous devez savoir ce qu'est une promesse en JavaScript.

Qu'est-ce que Promise.all?

Promise.all est en fait une promesse qui prend un tableau de promesses comme entrée (une itération). Ensuite, il est résolu lorsque toutes les promesses sont résolues ou que l'une d'entre elles est rejetée.

Par exemple, supposons que vous ayez dix promesses (opération Async pour effectuer un appel réseau ou une connexion à une base de données). Vous devez savoir quand toutes les promesses sont résolues ou vous devez attendre que toutes les promesses se résolvent. Vous passez donc les dix promesses à Promise.all. Ensuite, Promise.all lui-même en tant que promesse sera résolu une fois que toutes les dix promesses seront résolues ou que l'une des dix promesses sera rejetée avec une erreur.

Voyons cela dans le code:

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

Comme vous pouvez le voir, nous transmettons un tableau à Promise.all. Et lorsque les trois promesses sont résolues, Promise.all se résout et la sortie est consolé.

Voyons un exemple:

// 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"]

Dans l'exemple ci-dessus, Promise.all est résolu après 2000 ms et la sortie est consolidée sous forme de tableau.

Une chose intéressante à propos de Promise.all est que l'ordre des promesses est maintenu. La première promesse du tableau sera résolue en premier élément du tableau de sortie, la deuxième promesse sera un deuxième élément du tableau de sortie et ainsi de suite.

Voyons un autre exemple:

// 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"] 

D'après l'exemple ci-dessus, il est clair que Promise.all attend que toutes les promesses se résolvent.

Voyons ce qui se passe si l'une des promesses est rejetée.

// 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. 

Comme vous pouvez le voir, si l'une des promesses échoue, alors toutes les autres promesses échouent. Ensuite, Promise.all est rejeté.

Pour certains cas d'utilisation, vous n'en avez pas besoin. Vous devez exécuter toutes les promesses même si certaines ont échoué, ou peut-être pourrez-vous gérer les promesses ratées plus tard.

Voyons comment gérer cela.

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

Cas d'utilisation de Promise.all

Supposons que vous deviez effectuer un grand nombre d'opérations Async, comme l'envoi d'e-mails marketing en masse à des milliers d'utilisateurs.

Un pseudo-code simple serait:

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

L'exemple ci-dessus est simple. Mais ce n'est pas très performant. La pile deviendra trop lourde et à un moment donné, JavaScript aura un grand nombre de connexions HTTP ouvertes qui peuvent tuer le serveur.

Une approche simple et performante serait de le faire par lots. Prenez les 500 premiers utilisateurs, déclenchez le courrier et attendez que toutes les connexions HTTP soient fermées. Et puis prenez le prochain lot pour le traiter et ainsi de suite.

Voyons un exemple:

// Async function to send mail to a list of users. const sendMailForUsers = async (users) => { const usersLength = users.length for (let i = 0; i  { // 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)

Prenons un autre scénario: vous devez créer une API qui obtient des informations de plusieurs API tierces et agrège toutes les réponses des API.

Promise.all est le moyen idéal pour y parvenir. Voyons comment.

// 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 = `//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 }] */ 

Pour conclure, Promise.all est le meilleur moyen d'agréger un groupe de promesses en une seule promesse. C'est l'un des moyens d'obtenir la concurrence en JavaScript.

J'espère que vous avez aimé cet article. Si vous l'avez fait, applaudissez et partagez-le.

Même si vous ne l'avez pas fait, c'est bien, vous pouvez le faire quand même: P