promise.all_所有您需要了解的Promise.all

promise.all

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

JavaScript中的Promise是帮助我们执行异步操作的强大API之一。

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

Promise.all将Async操作提升到新的水平,因为它可以帮助您汇总一组Promise。

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.

您必须知道什么是JavaScript中的Promise

什么是Promise.all? (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.

Promise.all实际上是一个promise,它将一个promise作为输入(可迭代)。 然后,当所有承诺都得到解决或其中任何一个被拒绝时,它就会得到解决。

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.

例如,假设您有十个诺言(执行网络调用或数据库连接的异步操作)。 您必须知道所有诺言何时得到解决,或者必须等到所有诺言得到解决。 因此,您正在将所有十个承诺传递给Promise.all。 然后,一旦所有十个诺言都得到解决,或者十个诺言中的任何一个因错误而被拒绝,Promise.all本身作为一个诺言将被解决。

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.

如您所见,我们正在将数组传递给Promise.all。 当所有三个诺言都得到解决时,Promise.all就解决了,并且输出得到了控制。

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.

在上面的示例中,Promise.all在2000 ms之后解析,并且将输出作为数组进行控制台。

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.

关于Promise.all的一件有趣的事情是,承诺的顺序得以保持。 数组中的第一个promise将解析为输出数组的第一个元素,第二个promise将为输出数组中的第二个元素,依此类推。

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.

从上面的示例可以看出,Promise.all一直等到所有的诺言都化为乌有。

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.

如您所见,如果一个承诺失败,那么所有其他承诺都会失败。 然后Promise.all被拒绝。

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
Promise.all的用例 (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.

假设您必须执行大量的Async操作,例如向成千上万的用户发送批量营销电子邮件。

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.

上面的例子很简单。 但这不是很出色。 堆栈将变得太沉重,并且在某个时间点,JavaScript将具有大量开放的HTTP连接,这可能会杀死服务器。

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.

一种简单的执行方法是分批执行。 接收前500个用户,触发邮件,然后等到所有HTTP连接都关闭。 然后处理下一批,以此类推。

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.

让我们考虑另一种情况:您必须构建一个API,该API可从多个第三方API获取信息并汇总来自这些API的所有响应。

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

Promise.all是做到这一点的完美方法。 让我们看看如何。

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

总而言之,Promise.all是将一组诺言聚合为一个诺言的最佳方法。 这是在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

即使您没有,也可以这样做:P

翻译自: https://www.freecodecamp.org/news/promise-all-in-javascript-with-example-6c8c5aea3e32/

promise.all

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值