分组算法实现

需求

有多个calls数组,数组值分类且每个类别至多存放3个,多余的需要用存放在另一个同类数组,且calls表示用户的一组请求,要将用户在短时间内调用的calls,组合成大calls进行请求,并且返回对应的值

注:无法通过key来表示A1 也就是说A1不是唯一的,只能通过index

[A1,B1,C1]//calls
[A2,E1,D1]
[B2,B3,B4]
[B5,C2]

以上分类为
[A1,A2]
[B1,B2,B3]
[B4,B5]
[C1,C2]
[D1]
[E1]

将分类通过批量请求处理,会返回对应的值
[A1,A2]=>[A1_,A2_]
[B1,B2,B3] => [B1_,B2_,B3_]
[B4,B5] => [B4_,B5_] 
[C1,C2] => [C1_,C2_]
[D1] => [D1_]
[E1] => [E1_]

要求将对应值还原为初始的顺序结构
[A1_,B1_,C1_]
[A2_,E1_,D1_]
[B2_,B3_,B4_]
[B5_,C2_]

实现代码

   实现
  // 单个type容器最大量
  const MAX_CALLS = 3
  // debounce延迟
  const DELAY = 100

  // 定义分组id
  let groupId = {
    
    
    // 'type': 0
  }
  let callsId = 0
  let callsGroup = {
    
    
    // 'groupId_type': {calls,timeOut}
  }
  // 定义分组数据
  const resolveGroup = {
    
    
    // callsId: {resolve,calls}
  }

  // 处理分组下的请求是否都拿到了数据,拿到了就返回出去
  function checkedResult(){
    
    
    for (let i in resolveGroup) {
    
    
      const result = []
      for (let j = 0; j < resolveGroup[i].calls.length; j++) {
    
    
        if (!resolveGroup[i].calls[j].result){
    
    
          break
        } else {
    
    
          result.push(resolveGroup[i].calls[j].result)
        }
      }
      // 每个数据都有结果
      if (result.length === resolveGroup[i].calls.length){
    
    
        // 通过开始存储的resolve进行返回
        resolveGroup[i].resolve(result)
        delete resolveGroup[i]
      }
    }
  }

  function request(key){
    
    
    const callsData = callsGroup[key].calls
    // 用定时器模拟请求
    setTimeout(()=>{
    
    
      // 模拟请求结果
      const result = []
      for (let i = 0;i<callsData.length;i++) {
    
    
        result.push(callsData[i].params[0] + '_result')
      }
      // 将请求结果塞到原有的call
      for (let i = 0; i < callsData.length; i++) {
    
    
        callsData[i].result = result[i]
      }
      checkedResult()
    }, ~~Math.random()*500)
  }

  // 处理数据
  function handleData(calls){
    
    
    // 通过type分组
    for (let i = 0; i < calls.length; i++) {
    
    
      if (!groupId[calls[i].type]){
    
    
        groupId[calls[i].type] = 0
      }
      const key = `${
      
      groupId[calls[i].type]}_${
      
      calls[i].type}`
      if (callsGroup[key]) {
    
    
        callsGroup[key].calls.push(calls[i])
        // 当前type容器容器满了
        if (callsGroup[key].calls.length >= MAX_CALLS) {
    
    
          groupId[calls[i].type] += 1
        }
      } else {
    
    
        callsGroup[key] = {
    
    
          calls: [calls[i]]
        }
      }
    }
    // 处理calls
    for(let key in callsGroup){
    
    
      if (typeof callsGroup[key].timeOut !== 'undefined'){
    
    
        clearTimeout(callsGroup[key].timeOut)
      }
      // 满了就发请求
      if (callsGroup[key].calls.length >= MAX_CALLS){
    
    
        request(key)
      } else {
    
    
        // 未满就设置debounce
        callsGroup[key].timeOut = setTimeout(()=>{
    
    
          // debounce到了,没有进来新的calls,执行发请求
          request(key)
        }, DELAY)
      }
    }
  }

  function groupFn(calls){
    
    
    return new Promise((resolve => {
    
    
      resolveGroup[callsId ++] = {
    
    
        resolve,
        calls
      }
      handleData(calls)
    }))
  }

  / 调用
  
  // params为参数,是不固定的,以下按顺序写是为了方便观看结果
  const calls1 = [
    {
    
    type: 'a', params: ['a1']},
    {
    
    type: 'b', params: ['b1']},
    {
    
    type: 'c', params: ['c1']},
  ]
  const calls2 = [
    {
    
    type: 'a', params: ['a2']},
    {
    
    type: 'e', params: ['e1']},
    {
    
    type: 'd', params: ['d1']},
  ]
  const calls3 = [
    {
    
    type: 'b', params: ['b2']},
    {
    
    type: 'b', params: ['b3']},
    {
    
    type: 'b', params: ['b4']},
  ]
  const calls4 = [
    {
    
    type: 'b', params: ['b5']},
    {
    
    type: 'c', params: ['c2']},
  ]
  groupFn(calls1).then(res =>{
    
    
    console.log('calls1 result', res)
  })
  groupFn(calls2).then(res =>{
    
    
    console.log('calls2 result', res)
  })
  groupFn(calls3).then(res =>{
    
    
    console.log('calls3 result', res)
  })
  groupFn(calls4).then(res =>{
    
    
    console.log('calls4 result', res)
  })

以上代码为本人开发新版multicall核心算法,利用分组与对象本身引用特性实现

二次开发multicall中,也使用了类似的分组算法

分组算法逻辑,真的很常用…

猜你喜欢

转载自blog.csdn.net/weixin_43840202/article/details/121950955