代码之家  ›  专栏  ›  技术社区  ›  standup75

等待async变得更漂亮,但没有承诺那么多功能

  •  1
  • standup75  · 技术社区  · 7 年前

    下面是我使用wait/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秒。

    下面是我没有async/await的丑陋解决方案,只是承诺:

    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毫秒内完成任务

    能给我漂亮又高效的吗?

    1 回复  |  直到 7 年前
        1
  •  3
  •   Jannes Botis    7 年前

    上述代码的问题在于,您试图:

    1. 使用 一个承诺。全部() 为了所有的承诺
    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);
    

    改变的是

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

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

    处理承诺,例如:

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

    或者重复使用承诺,例如:

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

    工具书类

        2
  •  0
  •   s.d    7 年前

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

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