export async function lodaData() {
const res = await request.get('/api/data')
return res.data
}
/*
* 完成 asyncOnce函數(shù),函數(shù)接受一個(gè)異步函數(shù)作為參數(shù),
返回一個(gè)新的函數(shù),新的函數(shù)同時(shí)只能被調(diào)用一次,多次調(diào)用時(shí)返回第一次調(diào)用的結(jié)果。
*/
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))
})
})
}
}
//頁面上調(diào)用這個(gè)函數(shù),只會(huì)請求一次數(shù)據(jù)
export const getUseUser = asyncOnce(lodaData)
如果有參數(shù)的話該如何處理
export async function lodaData(id:number) {
const res = await request.get('/api/data',{params:{id}})
return res.data
}
/*
* 完成 asyncOnce函數(shù),函數(shù)接受一個(gè)異步函數(shù)作為參數(shù),
返回一個(gè)新的函數(shù),新的函數(shù)同時(shí)只能被調(diào)用一次,多次調(diào)用時(shí)返回第一次調(diào)用的結(jié)果。
*/
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
})
})
}
}
//頁面上調(diào)用這個(gè)函數(shù),只會(huì)請求一次數(shù)據(jù)
export const getUseUser = asyncOnce(lodaData)
asyncOnce 函數(shù)內(nèi)部定義了一個(gè) map 對象,用于存儲(chǔ)每個(gè)異步調(diào)用的狀態(tài)。
當(dāng)新函數(shù)被調(diào)用時(shí),它首先檢查 map 中是否已經(jīng)存在當(dāng)前調(diào)用參數(shù)的鍵(通過 JSON.stringify(args) 生成)。
如果不存在,說明這是第一次調(diào)用,將創(chuàng)建一個(gè)新的狀態(tài)對象,并將 isPending 設(shè)置為 false。
然后,將調(diào)用者的 resolve 和 reject 函數(shù)分別添加到狀態(tài)對象的 resolve 和 reject 數(shù)組中。
如果狀態(tài)對象的 isPending 為 true,則表示異步操作正在進(jìn)行中,直接返回,不重復(fù)執(zhí)行異步操作。
如果 isPending 為 false,則開始執(zhí)行異步操作,將 isPending 設(shè)置為 true。
異步操作完成后,使用 then 和 catch 分別處理成功和失敗的情況,并將結(jié)果傳遞給所有等待的 resolve 和 reject 函數(shù)。
最后,在 finally 回調(diào)中,將 map 中的當(dāng)前鍵值對設(shè)置為 null,以便釋放資源。