需求
有多个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中,也使用了类似的分组算法
分组算法逻辑,真的很常用…