我们是否需要比Promise.all更好的东西?

sta*_*p75 5 async-await es6-promise

这是我使用await / async的漂亮代码

monthlyBuckets(req, res) {
  const monthlyBuckets = []
  const now = DateTime.local()
  let date = config.beginningOfTime
  while (date < now) {
    monthlyBuckets.push({
      epoch: date.toMillis(),
      month: date.month,
      year: date.year,
      actions: await redis.get(`actions_monthly_${date.year}_${date.month}`),
      interested: await redis.scard(`sinterested_monthly_${date.year}_${date.month}`),
      adventurous: await redis.scard(`sadventurous_monthly_${date.year}_${date.month}`),
      active: await redis.scard(`sactive_monthly_${date.year}_${date.month}`),
    })
    date = date.plus({month: 1})
  }
  res.status(200).json(monthlyBuckets)
}
Run Code Online (Sandbox Code Playgroud)

我喜欢它,但是不并行执行这么多请求会导致请求时间接近3秒。

因此,这是我没有异步/等待的丑陋解决方案,只是承诺:

monthlyBuckets(req, res) {
    const monthlyBuckets = []
    const actions = []
    const interested = []
    const adventurous = []
    const active = []
    const now = DateTime.local()
    let date = config.beginningOfTime
    let entryCount = 0
    while (date < now) {
      monthlyBuckets.push({
        epoch: date.toMillis(),
        month: date.month,
        year: date.year,
      })
      actions.push(redis.get(`actions_monthly_${date.year}_${date.month}`))
      interested.push(redis.scard(`sinterested_monthly_${date.year}_${date.month}`))
      adventurous.push(redis.scard(`sadventurous_monthly_${date.year}_${date.month}`))
      active.push(redis.scard(`sactive_monthly_${date.year}_${date.month}`))
      date = date.plus({month: 1})
      entryCount++
    }
    const data = await Promise.all(actions.concat(interested).concat(adventurous).concat(active))
    for (let i = 0; i < entryCount; i++) {
      monthlyBuckets[i].actions = data[i]
      monthlyBuckets[i].interested = data[entryCount + i]
      monthlyBuckets[i].adventurous = data[entryCount * 2 + i]
      monthlyBuckets[i].active = data[entryCount * 3 + i]
    }
    res.status(200).json(monthlyBuckets)
  }
}
Run Code Online (Sandbox Code Playgroud)

这不是很漂亮,但是可以在200ms内完成工作

我能拥有漂亮又高效的吗?

Jan*_*tis 3

上面代码的问题是您试图:

  1. 对所有 Promise使用一个 Promise.all()
  2. 在一个回调中处理所有响应的输出

虽然这不是一个错误,但它可能会导致代码难以“阅读”。

代码可以写成:

while (date < now) {
  let dateData = {
    epoch: date.toMillis(),
    month: date.month,
    year: date.year,
  };
  let promiseData = Promise.all([
      dateData, // dataData is cast(made to) automatically into a promise
      redis.get(`actions_monthly_${date.year}_${date.month}`),
      redis.scard(`sinterested_monthly_${date.year}_${date.month}`),
      redis.scard(`sadventurous_monthly_${date.year}_${date.month}`),
      redis.scard(`sactive_monthly_${date.year}_${date.month}`)
  ]).then([data, actions, interested, adventurous, active] => {
      // process the data here for each month
      data.actions = actions;
      data.interested = interested;
      data.adventurous = adventurous;
      data.active = active;
      return data;
});
  monthlyBuckets.push(promiseData);
  date = date.plus({month: 1});
}

const data = await Promise.all(monthlyBuckets);
res.status(200).json(data);
Run Code Online (Sandbox Code Playgroud)

改变的是

  • 对每个月的承诺进行分组
  • 处理一个月的一组承诺,而不是所有承诺一起并按需要返回数据。

将 Promise 分组没有任何问题,例如:

Promise.all([
       Promise.all([ ...]),
       Promise.all([ ...]),
       singlePromise,
       ...
]);
Run Code Online (Sandbox Code Playgroud)

处理承诺例如:

promiseProcessed1 = promise1.then(callback1);
promiseProcessed12 = Promise.all([promise1, promise2]).then(callback2);
Run Code Online (Sandbox Code Playgroud)

或重用承诺,例如:

promiseProcessed1 = promise1.then(callback1);
promiseProcessed12 = Promise.all([promise1, promise2]).then(callback2);
resultDatapromise = Promise.all([promise1, promise2, promiseProcessed1, promiseProcessed12]).then(callback2);
Run Code Online (Sandbox Code Playgroud)

参考