如何避免相同的请求重复发送

2024-12-26  本文已影响0人  rainy66
export async function lodaData() {
  const res =  await request.get('/api/data')
  return res.data
}

/*
* 完成 asyncOnce函数,函数接受一个异步函数作为参数,
返回一个新的函数,新的函数同时只能被调用一次,多次调用时返回第一次调用的结果。
 */

export function asyncOnce(cb:(...args:any[])=>Promise<any>){
  let isPending = false
  const stack:any[] = []
  return () => {
    return new Promise((resolve,reject) => {
      if(isPending) {
        stack.push(resolve,reject)
        return
      }
      isPending = true
      cb().then((res) => {
        resolve(res)
        stack.forEach(({resolve})=>resolve(res))
      }).catch((err) => {
        reject(err)
        stack.forEach(({reject})=>reject(err))
      })
    })
  }
}

//页面上调用这个函数,只会请求一次数据
export const getUseUser = asyncOnce(lodaData)

如果有参数的话该如何处理

export async function lodaData(id:number) {
  const res =  await request.get('/api/data',{params:{id}})
  return res.data
}

/*
* 完成 asyncOnce函数,函数接受一个异步函数作为参数,
返回一个新的函数,新的函数同时只能被调用一次,多次调用时返回第一次调用的结果。
*/

export function asyncOnce(cb:(...args:any[])=>Promise<any>){
  const map:Record<string,{
    resolve:((value: any) => void)[],
    reject:((err?: any) => void)[],
    isPending:boolean
  } | null> = {}
  return(...args:any[]) => {
    return new Promise((resolve,reject) => {
      const key = JSON.stringify(args)
      if(!map[key]){
        map[key] = {
          resolve:[],
          reject:[],
          isPending:false
        }
      }
      const state = map[key]
      state.resolve.push(resolve)
      state.reject.push(reject)
      if(state.isPending)return
      state.isPending = true
      cb(...args).then((res) => {
        state.resolve.forEach(resolve => resolve(res))
      }).catch((err) => {
        state.reject.forEach(reject => reject(err))
      }).finally(()=>{
        map[key] = null
      })
    })
  }
}
//页面上调用这个函数,只会请求一次数据
export const getUseUser = asyncOnce(lodaData)

asyncOnce 函数内部定义了一个 map 对象,用于存储每个异步调用的状态。
当新函数被调用时,它首先检查 map 中是否已经存在当前调用参数的键(通过 JSON.stringify(args) 生成)。
如果不存在,说明这是第一次调用,将创建一个新的状态对象,并将 isPending 设置为 false。
然后,将调用者的 resolve 和 reject 函数分别添加到状态对象的 resolve 和 reject 数组中。
如果状态对象的 isPending 为 true,则表示异步操作正在进行中,直接返回,不重复执行异步操作。
如果 isPending 为 false,则开始执行异步操作,将 isPending 设置为 true。
异步操作完成后,使用 then 和 catch 分别处理成功和失败的情况,并将结果传递给所有等待的 resolve 和 reject 函数。
最后,在 finally 回调中,将 map 中的当前键值对设置为 null,以便释放资源。

上一篇 下一篇

猜你喜欢

热点阅读