zoukankan      html  css  js  c++  java
  • 思索-js 页面ID识别及数据缓存

    思索-页面ID识别及数据缓存

    页面 ID 识别的思路

    多页应用在移动端是较为常见的一种架构,它可以和APP 内的 webview 配合,达到类似原生的体验,这一点是单页应用无法做到的(比如手势滑动等,会直接关闭 webview)。

    多页应用中,使用location 进行跳转时页面会被销毁,页面后退或刷新时,页面就会是一个全新的加载,在一些需要页面级的缓存数据时,没办法通过简单的 sessionStorage 进行缓存,主要是因为 sessionStorage 生命周期存在一个上下文,与本页面关联,或者重新进入本页面的时候都会一直存在。而我们要做到的效果是:刷新/后退时页面数据缓存,重新进入页面不缓存。

    为什么我们难以实现页面 ID 的识别?因为页面本身是无状态的,如果 URL 唯一,那么可以把 URL 当作是页面的 ID,如果页面入口不是自己控制,那我们没办法保证 URL 会是唯一的。想要给页面加个 ID,最先想到的是自己维护一套 history,每次生成时候保存页面 ID,根据前进或者是后退来识别当前页面位于哪个位置。

    判断页面的前进后退,我们可以用浏览器提供的接口:performance.navigation.type 来判断(参见:https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigationTiming,

    function getNaviagteType () {
      const { performance } = window
    
      // performance navigation 兼容 ios9+, Android 全部, 低于该版本默认全部是新打开
      if (performance) {
        // 新的 performance 接口
        if (typeof performance.getEntriesByType === 'function') {
          const perfEntries = performance.getEntriesByType('navigation') || []
          const [timing] = perfEntries
          if (timing && timing.type) {
            return timing.type
          }
        }
    
        const typeMap = ['navigate', 'reload', 'back_forward']
        // 旧的 performance 接口
        if (performance.navigation && performance.navigation.type != null) {
          return typeMap[performance.navigation.type] || 'reserved'
        }
      }
      return 'not_support'
    }
    

    根据这个来判断,我们就可以拿到需要的导航类型。这样和 sessionStorage 配合,就可以维护一套可用的历史记录版本了。但是如果我们只是要页面ID 级别的缓存呢?

    页面级别数据缓存

    如果只需要数据缓存,我们就不需要考虑维护 ID 了。因为正常情况下我们的历史记录里面不会出现两次一样的 URL,或者是出现也不影响我们的页面表现。具体代码如下:

    
    const SESSION_KEY = 'page-cache'
    
    const { sessionStorage } = window
    
    function safeJsonParse(str, defaultValue) {
      if (!str) {
        return defaultValue;
      }
      let res
      try {
        res = JSON.parse(str)
      } catch (err) {
        // eslint-disable-next-line no-console
        console.error(err)
        res = defaultValue
      }
      return res || defaultValue
    }
    
    /**
     * 初始化页面数据
     * @param {*} cacheData 数据对象
     * @param {*} pageId 页面ID
     * @param {*} usePreData 是否使用上次缓存的值
     */
    function initPageData (cacheData, pageId, usePreData) {
      const initData = cacheData
      initData.pageId = pageId
      initData.data = initData.data || {}
      initData.data[pageId] = (usePreData ? initData.data[pageId] : null) || {}
    
      sessionStorage.setItem(SESSION_KEY, JSON.stringify(initData))
    }
    /**
     * 初始化页面数据
     */
    function init (pageId = window.location.pathname) {
      const cacheData = safeJsonParse(sessionStorage.getItem(SESSION_KEY), {})
      const navType = getNaviagteType()
      // 这几种情况下不清除数据,直接沿用上一次数据
      if (cacheData.pageId && ['back_forward', 'reload', 'not_support'].indexOf(navType) > -1) {
        initPageData(cacheData, pageId, true)
        return cacheData
      }
    
      initPageData(cacheData, pageId, false)
      return cacheData
    }
    init()
    
    /**
     * 获取全量的 cache 数据
     */
    function getFullCacheData () {
      const cacheData = safeJsonParse(sessionStorage.getItem(SESSION_KEY), null)
      return cacheData || init()
    }
    /**
     * 获取缓存中的数据
     */
    function getPageCache (cacheData = getFullCacheData()) {
      return cacheData.data[cacheData.pageId] || {}
    }
    
    /**
     * 获取缓存中指定 key 的数据
     * @param {*} key key 值
     */
    function getPageCacheItem (key) {
      const cacheData = getPageCache()
      return cacheData[key]
    }
    
    /**
     * 设置缓存内容
     * @param {*} key key
     * @param {*} value 对应的数据
     */
    function setPageCacheItem (key, value) {
      const fullData = getFullCacheData()
      const cacheData = getPageCache(fullData)
      cacheData[key] = value
      sessionStorage.setItem(SESSION_KEY, JSON.stringify(fullData))
    }
    
    /**
     * 移除缓存中页面的某个数据
     * @param {*} key 条目名称
     */
    function removePageCacheItem (key) {
      const fullData = getFullCacheData()
      const cacheData = getPageCache(fullData)
      delete cacheData[key]
      sessionStorage.setItem(SESSION_KEY, JSON.stringify(fullData))
    }
    
    /**
     * 移除缓存
     */
    function clearPageCache () {
      const fullData = getFullCacheData()
      fullData.data[fullData.pageId] = {}
      sessionStorage.setItem(SESSION_KEY, JSON.stringify(fullData))
    }
    
    const cache = {
      init,
      getAll: getPageCache,
      getItem: getPageCacheItem,
      setItem: setPageCacheItem,
      removeItem: removePageCacheItem,
      clear: clearPageCache
    }
    

    该方案的主要缺陷是:

    • 不兼容 IOS9,所以需要考虑到失效情况下你的业务是什么表现
    • 历史记录里面存在相同的url,那缓存数据会产生污染

    如果你有兴趣的话,可以实现一个页面 ID 的功能,在初始化的时候设置 pageId 的值就可以了。

  • 相关阅读:
    查看单据项目文本对应的参数信息
    下载EPM包详细运行日志
    ABAP 字符串换行符处理
    PyCharm编辑HTML文件时输入{%不能自动补全
    Ubuntu 18.04安装MongoDB 4.0
    ubuntu18.04(bionic) 配置阿里数据源
    【Python】迭代器
    【python】多任务(2. 进程)
    【python】多任务(1. 线程)
    【python】文件下载---基础版
  • 原文地址:https://www.cnblogs.com/dreamless/p/13546148.html
Copyright © 2011-2022 走看看