前端分批发送请求,控制并发请求数量

113 阅读1分钟

场景:有个列表,每个列表前面有个【展开】按钮,点击按钮,调接口查到详情显示到列表下面

image.png

现在,用户觉得一个个地点按钮太慢了,能不能给个【全部展开】按钮,一键展开所有,那当然能了

动画.gif

这样便有了高并发的场景

实现以上效果代码:

<template>
  <div>
    <el-button type="primary" @click="handleExpandAll">全部展开</el-button>
    <ul>
      <li v-for="(item, index) of list" :key="item.purchaseOrderId">
        <div class="row">
          <el-button @click="handleExpand(item.purchaseOrderId, index)">展开</el-button>
          <div>ID:{{ item.purchaseOrderId }}</div>
          <div>采购订单:{{ item.number }}</div>
        </div>
        <div class="detail-wrapper">
          <p v-for="{ purchasePaymentMethodId } of item.paymentMethodShowListVO">
            {{ purchasePaymentMethodId }}
          </p>
        </div>
      </li>
    </ul>
  </div>
</template>

<script>
import { list } from './data'
import { getPurchaseOrderPayShow } from '@/api/request'

export default {
  name: 'ConcurrentRequest',
  data() {
    return { list }
  },
  methods: {
    async handleExpandAll() {
      const ids = this.list.map(item => item.purchaseOrderId)
      ids.forEach((purchaseOrderId, index) => {
        this.handleExpand(purchaseOrderId, index)
      })
    },
    async handleExpand(purchaseOrderId, index) {
      const { paymentMethodShowListVO } = await getPurchaseOrderPayShow(purchaseOrderId)
      this.$set(this.list[index], 'paymentMethodShowListVO', paymentMethodShowListVO)
    }
  }
}
</script>
<style lang="less" scoped>
li {
  margin-top: 20px;
  .row {
    display: flex;
    align-items: center;
  }
  .detail-wrapper {
    background-color: yellowgreen;
  }
}
</style>


data.js

点击展开/折叠
export const list = [
  {
    number: 'CRP250180592',
    purchaseOrderId: '1063400305661599775',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13],
  },
  {
    number: 'CRP250121837',
    purchaseOrderId: '1063400316252217346',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250128558',
    purchaseOrderId: '1063400322895994926',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250133276',
    purchaseOrderId: '1063400328445059133',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250116201',
    purchaseOrderId: '1063400334304501850',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250128282',
    purchaseOrderId: '1063400339786457105',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250154845',
    purchaseOrderId: '1063400345092251688',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250152008',
    purchaseOrderId: '1063400352100933675',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250114090',
    purchaseOrderId: '1063400358056845382',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250156728',
    purchaseOrderId: '1063400365145219095',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250183207',
    purchaseOrderId: '1063400371176628283',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250133398',
    purchaseOrderId: '1063400376885076020',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250138352',
    purchaseOrderId: '1063400382153121794',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250130245',
    purchaseOrderId: '1063400388377468941',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250131801',
    purchaseOrderId: '1063400393846841442',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250175354',
    purchaseOrderId: '1063400400700334132',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250167729',
    purchaseOrderId: '1063400406702383129',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250177636',
    purchaseOrderId: '1063400412171755523',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250154840',
    purchaseOrderId: '1063400417787928653',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250155526',
    purchaseOrderId: '1063400424104550443',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250140754',
    purchaseOrderId: '1063400430685413452',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250136594',
    purchaseOrderId: '1063400438864306228',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250135925',
    purchaseOrderId: '1063400447965945941',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250175053',
    purchaseOrderId: '1063400454970433556',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250156566',
    purchaseOrderId: '1063400460523692118',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250120582',
    purchaseOrderId: '1063400465904984137',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250179983',
    purchaseOrderId: '1063400471642791990',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250188696',
    purchaseOrderId: '1063400478164934679',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250141539',
    purchaseOrderId: '1063400485748236293',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250114375',
    purchaseOrderId: '1063400494308810832',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250147701',
    purchaseOrderId: '1063400500528963652',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250170999',
    purchaseOrderId: '1063400505998336043',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250182860',
    purchaseOrderId: '1063400511241216076',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250191740',
    purchaseOrderId: '1063400517616558085',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250130582',
    purchaseOrderId: '1063400524813983810',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250111221',
    purchaseOrderId: '1063400530635677784',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250190213',
    purchaseOrderId: '1063400536440594500',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250178883',
    purchaseOrderId: '1063400542048378893',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250163105',
    purchaseOrderId: '1063400547572277306',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250169419',
    purchaseOrderId: '1063400552718688258',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250195884',
    purchaseOrderId: '1063400558313889857',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250118980',
    purchaseOrderId: '1063400565083496533',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250180860',
    purchaseOrderId: '1063400571316232200',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250152309',
    purchaseOrderId: '1063400583337107470',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250181724',
    purchaseOrderId: '1063400589125247043',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250196333',
    purchaseOrderId: '1063400594724642857',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250179968',
    purchaseOrderId: '1063400599682310187',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250110299',
    purchaseOrderId: '1063400605722107951',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250188674',
    purchaseOrderId: '1063400612458160179',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  },
  {
    number: 'CRP250123547',
    purchaseOrderId: '1063400618309214273',
    state: 5,
    stateNote: '采购中',
    creator: '吴真真',
    buyerNameEn: 'Ainling_Zhang',
    buyerEnName: 'Ainling_Zhang',
    taxRateList: [0.13]
  }
]

如何做到每次发送3个请求,当这次的3个请求成功后,再发送下次的3个请求

    async handleExpandAll() {
      const ids = this.list.map(item => item.purchaseOrderId)
      // ids.forEach((purchaseOrderId, index) => {
      //   this.handleExpand(purchaseOrderId, index)
      // })
      const batchSize = 3
      for (let i = 0; i < ids.length; i += batchSize) {
        const batch = ids.slice(i, i + batchSize)

        // 执行并等待当前批次的所有请求完成
        await Promise.all(
          batch.map((purchaseOrderId, index) => {
            const actualIndex = i + index // 计算实际索引
            return this.handleExpand(purchaseOrderId, actualIndex)
          })
        )
      }
    },

效果:

动画.gif

如果有多个场景都需要控制并发数量,可以封装成函数:

    async concurrencyRequest(ids, api, maxNum = 6) {
      const resList = []
      for (let i = 0; i < ids.length; i += maxNum) {
        const batchIds = ids.slice(i, i + maxNum)
        const res = await Promise.all(batchIds.map(async id => await api(id)))
        resList.push(...res)
      }
      return resList
    }

完整代码:

<template>
  <div>
    <el-button type="primary" @click="handleExpandAll">全部展开</el-button>
    <ul>
      <li v-for="(item, index) of list" :key="item.purchaseOrderId">
        <div class="row">
          <el-button @click="handleExpand(item.purchaseOrderId, index)">展开</el-button>
          <div>ID:{{ item.purchaseOrderId }}</div>
          <div>采购订单:{{ item.number }}</div>
        </div>
        <div class="detail-wrapper">
          <p v-for="{ purchasePaymentMethodId } of item.paymentMethodShowListVO">
            {{ purchasePaymentMethodId }}
          </p>
        </div>
      </li>
    </ul>
  </div>
</template>

<script>
import { list } from './data'
import { getPurchaseOrderPayShow } from '@/api/request'

export default {
  name: 'ConcurrentRequest',
  data() {
    return { list: list.slice(0, 10) }
  },
  methods: {
    async handleExpandAll() {
      const ids = this.list.map(item => item.purchaseOrderId)
      const res = await this.concurrencyRequest(ids, getPurchaseOrderPayShow)
      console.log('res', res)
      res.forEach((item, index) => {
        this.$set(this.list[index], 'paymentMethodShowListVO', item.paymentMethodShowListVO)
      })
    },
    async handleExpand(purchaseOrderId, index) {
      const { paymentMethodShowListVO } = await getPurchaseOrderPayShow(purchaseOrderId)
      this.$set(this.list[index], 'paymentMethodShowListVO', paymentMethodShowListVO)
    },
    async concurrencyRequest(ids, api, maxNum = 6) {
      const resList = []
      for (let i = 0; i < ids.length; i += maxNum) {
        const batchIds = ids.slice(i, i + maxNum)
        const res = await Promise.all(batchIds.map(async id => await api(id)))
        resList.push(...res)
      }
      return resList
    }
  }
}
</script>
<style lang="less" scoped>
li {
  margin-top: 20px;
  .row {
    display: flex;
    align-items: center;
  }
  .detail-wrapper {
    background-color: yellowgreen;
  }
}
</style>

效果:

动画.gif 方便测试,可以ajax将改写成fetch请求:

    async handleExpand(purchaseOrderId, index) {
      // const { paymentMethodShowListVO } = await getPurchaseOrderPayShow(purchaseOrderId)
      // this.$set(this.list[index], 'paymentMethodShowListVO', paymentMethodShowListVO)
      const res = await fetch(
        `/erp/finance/payOrder/getPurchaseOrderPayShow?purchaseOrderId=${purchaseOrderId}&number=FK25023633915`,
        { headers: { tokenId: this.token } }
      ).then(async response => {
        return await response.json()
      })
      const { paymentMethodShowListVO } = res.data
      this.$set(this.list[index], 'paymentMethodShowListVO', paymentMethodShowListVO)
    },

如果你觉得这篇文章对你有用,可以看看作者封装的库xtt-utils,里面封装了非常实用的js方法。如果你也是vue开发者,那更好了,除了常用的api,还有大量的基于element-ui组件库二次封装的使用方法和自定义指令等,帮你提升开发效率。不定期更新,欢迎交流~