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

时间:2019-01-26 02:04:13

标签: 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)
}

我喜欢它,但是不并行执行这么多请求会导致请求时间接近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)
  }
}

不好看,但是可以在200毫秒内完成工作

我能拥有漂亮高效吗?

2 个答案:

答案 0 :(得分:3)

上面的代码存在问题,您正在尝试:

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

尽管这不是一个错误,但可能导致难以“阅读”代码。

代码可以写为:

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

改变的是

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

分组承诺没有错,例如:

Promise.all([
       Promise.all([ ...]),
       Promise.all([ ...]),
       singlePromise,
       ...
]);

处理承诺,例如:

promiseProcessed1 = promise1.then(callback1);
promiseProcessed12 = Promise.all([promise1, promise2]).then(callback2);

或重用promise,例如:

promiseProcessed1 = promise1.then(callback1);
promiseProcessed12 = Promise.all([promise1, promise2]).then(callback2);
resultDatapromise = Promise.all([promise1, promise2, promiseProcessed1, promiseProcessed12]).then(callback2);

参考

答案 1 :(得分:0)

在这种情况下,采取不同的步骤可能会有所帮助。示例:

function createBucket(date, ops){
    const b = {
        epoch: date.toMillis(),
        month: date.month,
        year: date.year,
        actions: redis.get(`actions_monthly_${date.year}_${date.month}`),
        interested: redis.scard(`sinterested_monthly_${date.year}_${date.month}`),
        adventurous: redis.scard(`sadventurous_monthly_${date.year}_${date.month}`),
        active: redis.scard(`sactive_monthly_${date.year}_${date.month}`),
    }

    const promised = ['actions','interested', 'adventurous', 'active'];
    promised.forEach(p => ops.push(async () => {b[p] = await b[p]}));
}

async function monthlyBuckets(req,res){
    const monthlyBuckets = []
    const now = DateTime.local()
    let date = config.beginningOfTime

    const ops = [];
    while (date < now) {
      monthlyBuckets.push(createBucket(date,ops));
      date = date.plus({month: 1})
    }

    await Promise.all(ops);
    res.status(200).json(monthlyBuckets)
}