侧边栏壁纸
  • 累计撰写 218 篇文章
  • 累计创建 59 个标签
  • 累计收到 5 条评论

基于浏览器缓存的渐进式 Composable API

barwe
2023-05-10 / 0 评论 / 0 点赞 / 722 阅读 / 2,327 字
温馨提示:
本文最后更新于 2023-05-10,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

下面是一个用于本地缓存存取的工具类:

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 缓存,后请求数据的方式,减少页面空白页的持续时间。

0

评论区