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

时间:2019-07-18 07:57:26

标签: javascript node.js asynchronous 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())

然后我使用了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))

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

1 个答案:

答案 0 :(得分:5)

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

        const todayVisitorsCount = await Session.count({...})
        const yesterdayVisitorsCount = await UserSession.count({...})

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

const data = await Promise.all(allPromises)

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

const fn = () => new Promise(resolve => setTimeout(resolve, 1000));

console.log('start');
(async () => {
  await fn();
  await fn();
  console.log('two awaits done');
})();

(async () => {
  await Promise.all([fn(), fn()]);
  console.log('Promise.all done');
})();

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

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

因此,Promise.all版本的运行速度比具有两个await的版本运行更快。最好使用Promise.all,除非第一个Promise(UserSession.count 必须先在第二个Promise(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 });
  });
}