Promise.all或嵌套异步等待哪个更好?

Pro*_*fer 2 javascript asynchronous node.js promise async-await

我有两个代码块。首先是使用async await

  async sendEmailNotifications() {
    try {
      const users = await User.find(...)

      const promises = users.map(async(user) => {
        const _promises = user.appId.map(async(app) => {
            const todayVisitorsCount = await Session.count({...})
            const yesterdayVisitorsCount = await UserSession.count({...})
            const emailObj = {
              todayVisitorsCount,
              yesterdayVisitorsCount
            }
            const sendNotification = await emailService.analyticsNotification(emailObj)
        })
        await Promise.all(_promises)
      })
      return promises
    } catch (err) {
      return err
    }
  }
(await sendEmailNotifications())
Run Code Online (Sandbox Code Playgroud)

然后我有使用 Promise.all

    sendEmailNotifications() {
      const users = await User.find(...)
      const promises = users.map((user) => {
        const allPromises = []
        user.appId.map((app) => {
          allPromises.push(UserSession.count({...}))
          allPromises.push(Session.count({...}))
        })
        const data = await Promise.all(allPromises)
        const emailObj = {
          todayVisitorsCount: data[0],
          yesterdayVisitorsCount: data[1]
        }
        const sendNotification = await emailService.analyticsNotification(emailObj)
      })
      return promises
  }


  sendNotification.then((data) => console.log(data))
Run Code Online (Sandbox Code Playgroud)

现在我需要知道哪段代码可以更快地执行?一种是使用series(异步等待),另一种是使用parellel(Promise.all)。哪个有更好的表现?

Cer*_*nce 5

在第一个代码中,您有两个单独的await语句:

        const todayVisitorsCount = await Session.count({...})
        const yesterdayVisitorsCount = await UserSession.count({...})
Run Code Online (Sandbox Code Playgroud)

而在第二个中,在a之前只有一个Promise.all

const data = await Promise.all(allPromises)
Run Code Online (Sandbox Code Playgroud)

在第一个代码中,第二个Promise仅在第一个Promise完成后才初始化,从而导致脚本结束之前需要更长的时间。例如:

        const todayVisitorsCount = await Session.count({...})
        const yesterdayVisitorsCount = await UserSession.count({...})
Run Code Online (Sandbox Code Playgroud)

没有版本的版本会Promise.all在第一次调用时暂停该功能fn(),并等待返回的Promise fn()解析(1000毫秒),然后继续进行下一行。下一行fn()再次调用,并await等待其完成(另外1000毫秒)。

相反,该Promise.all版本会fn()立即调用s-两个Promises都已初始化,并且await暂停该函数的函数正在等待两个 Promises完成。在第一个Promise的初始化和第二个Promise的初始化之间没有停机时间。

因此,该Promise.all版本将比带有2 awaits 的版本运行更快。使用Promise.all将是优选的,除非第一无极(UserSession.count必须在第二无极(前完成Session.count)开始。

通过解构并且没有不必要的变量,这就是我清理Promise.all代码的方式,您可能会认为它更具可读性:

async sendEmailNotifications() {
  const users = await User.find();
  return users.map(async (user) => {
    const [todayVisitorsCount, yesterdayVisitorsCount] = await Promise.all([
      UserSession.count(),
      Session.count()
    ]);
    await emailService.analyticsNotification({ todayVisitorsCount, yesterdayVisitorsCount });
  });
}
Run Code Online (Sandbox Code Playgroud)

  • 另一种(被认为是不太可能的)场景是,如果Session.count和UserSession.count由于某种奇怪的原因以一种不好的方式交互,并且如果一起运行(例如奇怪的数据库争用?)会花费更长的时间,那么串行的结束速度将比平行...正如我所说,虽然不太可能,但在某些情况下值得牢记。 (2认同)
  • 不是“初始化承诺”,而是“开始运营”。这就是重点。`await Session.count({})`后跟`await User.count({})`意味着直到`Session.count({})`的诺言才调用User.count({})履行,因此直到`Session.count({})`的承诺履行之前,它才开始运行。如果操作应并行进行,则必须先将它们同时启动,然后等待其结果,这一点很重要。 (2认同)
  • @Profer`await`不是* Promise.all`的替代品-他们做了两件事。在大多数情况下,await可以代替Promise.prototype.then,从而使异步代码看起来更平整且更具可读性。了解此页面上所有代码段如何使用`await`-有用*,无论是否使用`Promise.all`。Promise.all返回一个Promise,该Promise在传递的Promises数组中的每个解析时进行解析,这在某些情况下(包括此情况)也很有用。 (2认同)