Alt hvad du behøver at vide om Promise.all

Løfter i JavaScript er en af ​​de stærke API'er, der hjælper os med at udføre Async-operationer.

Promise.all tager Async-operationer til det næste nye niveau, da det hjælper dig med at samle en gruppe løfter.

Med andre ord kan jeg sige, at det hjælper dig med at udføre samtidige operationer (nogle gange gratis).

Forudsætninger:

Du skal vide, hvad der er et løfte i JavaScript.

Hvad er Promise.all?

Promise.all er faktisk et løfte, der tager en række løfter som input (en iterabel). Derefter løses det, når alle løfter løses, eller hvis nogen af ​​dem bliver afvist.

Antag for eksempel, at du har ti løfter (Async-handling til at udføre et netværksopkald eller en databaseforbindelse). Du skal vide, hvornår alle løfter løses, eller du skal vente, indtil alle løfter løses. Så du overlever alle ti løfter til Promise.all. Så løfter Promise.all sig selv som et løfte, når alle de ti løfter bliver løst, eller et af de ti løfter bliver afvist med en fejl.

Lad os se det i kode:

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

Som du kan se, sender vi en matrix til Promise.all. Og når alle tre løfter løses, løses Promise.all, og output trøstes.

Lad os se et eksempel:

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

I ovenstående eksempel løses Promise.all efter 2000 ms, og output trøstes som en matrix.

En interessant ting ved Promise.all er, at løfteordren opretholdes. Det første løfte i arrayet bliver løst til det første element i output arrayet, det andet løfte vil være et andet element i output arrayet og så videre.

Lad os se et andet eksempel:

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

Fra ovenstående eksempel er det klart, at Promise.all venter, indtil alle løfter løses.

Lad os se, hvad der sker, hvis et af løfterne afvises.

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

Som du kan se, hvis et af løfterne fejler, fejler alle resten af ​​løfterne. Så bliver Promise.all afvist.

For nogle brugssager har du ikke brug for det. Du er nødt til at udføre alle løfterne, selvom nogle har fejlet, eller måske kan du håndtere de mislykkede løfter senere.

Lad os se, hvordan vi skal håndtere det.

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

Brug tilfælde af Promise.all

Antag, at du skal udføre et stort antal Async-operationer som at sende bulk marketing-e-mails til tusindvis af brugere.

Enkel pseudokode ville være:

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

Ovenstående eksempel er ligetil. Men det er ikke særlig performant. Stakken bliver for tung, og på et tidspunkt vil JavaScript have et stort antal åben HTTP-forbindelse, som kan dræbe serveren.

En simpel performant tilgang ville være at gøre det i batches. Tag de første 500 brugere, udløs e-mailen, og vent, indtil alle HTTP-forbindelser er lukket. Og tag derefter det næste parti for at behandle det og så videre.

Lad os se et eksempel:

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

Lad os overveje et andet scenario: Du skal opbygge en API, der får oplysninger fra flere tredjeparts-API'er og samler alle svarene fra API'erne.

Promise.all er den perfekte måde at gøre det på. Lad os se hvordan.

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

Afslutningsvis er Promise.all den bedste måde at samle en gruppe løfter til et enkelt løfte. Dette er en af ​​måderne til at opnå samtidighed i JavaScript.

Håber du kunne lide denne artikel. Hvis du gjorde det, bedes du klappe og dele det.

Selvom du ikke gjorde det, er det fint, du kan gøre det alligevel: P