下面是一个用于本地缓存存取的工具类:
import localforage from 'localforage'
type StorageType = 'sessionStorage' | 'localStorage' | 'localforage'
class CacheIO<T> {
private key: string
private storage: StorageType
constructor(key: string, storage: StorageType) {
this.key = key
this.storage = storage
}
public async getData() {
if (this.storage === 'sessionStorage') {
const cached = sessionStorage.getItem(this.key)
if (cached === null) return null
return JSON.parse(cached) as T
} else if (this.storage === 'localStorage') {
const cached = localStorage.getItem(this.key)
if (cached === null) return null
return JSON.parse(cached) as T
} else {
const cached = await localforage.getItem<T>(this.key)
if (cached === null) return null
return cached
}
}
public async setData(data: T) {
if (this.storage === 'sessionStorage') {
const str = JSON.stringify(data)
sessionStorage.setItem(this.key, str)
} else if (this.storage === 'localStorage') {
const str = JSON.stringify(data)
localStorage.setItem(this.key, str)
} else {
await localforage.setItem<T>(this.key, data)
}
}
}
基于该工具类设计一个结合缓存和请求的渐进式请求工具:
interface Option {
/** 用于缓存的 key */
key: string
/**
* 缓存方式:sessionStorage, localStorage, localforage。
* 默认 sessionStorage
* */
storage?: StorageType
/** 何时发起请求,默认 cache-loaded */
mode?:
| 'only-no-cache' // 本地没有缓存时
| 'cache-loaded' // 本地缓存加载完成后
| 'manual' // 通过 run 手动发起请求
/** 是否禁用缓存,默认 false */
disableCache?: boolean
}
export function useProgressiveRequest<T>(
loader: () => Promise<T>,
options: Option
) {
const data = ref<T>()
const isCacheAvailable = ref<boolean>()
const isCacheLoaded = ref(false)
const isCacheUpdated = ref(false)
const isRemoteLoaded = ref(false)
const storage = options.storage ?? 'sessionStorage'
const io = new CacheIO<T>(options.key, storage)
if (options.disableCache) {
isCacheAvailable.value = false
} else {
io.getData().then(cached => {
if (cached) data.value = cached
isCacheAvailable.value = !!cached
isCacheLoaded.value = true
})
}
const run = async () => {
const rd = await loader()
io.setData(rd).then(() => {
isCacheUpdated.value = true
})
data.value = rd
isRemoteLoaded.value = true
}
const mode = options.mode ?? 'cache-loaded'
// 缓存加载完成后立即请求新的数据
if (mode === 'cache-loaded') {
watchOnce(isCacheLoaded, run)
}
// 只在没有缓存时请求新的数据
else if (mode === 'only-no-cache') {
watchOnce(isCacheAvailable, v => {
if (!v) run()
})
}
// 手动发起请求
// else if (mode === 'manual') {}
return {
data,
run,
/** 本地缓存是否可用 */
isCacheAvailable,
/** 本地缓存是否已加载 */
isCacheLoaded,
/** 请求新数据后本地缓存是否已更新 */
isCacheUpdated,
/** 新数据是否已请求完成 */
isRemoteLoaded,
}
}
该 API 可替代传统的请求方法,默认使用先加载 sessionStorage 缓存,后请求数据的方式,减少页面空白页的持续时间。
评论区