思索-页面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 的值就可以了。

思索-js 页面ID识别及数据缓存的更多相关文章

  1. 从微信小程序到鸿蒙js开发【12】——storage缓存&自动登录

    鸿蒙入门指南,小白速来!从萌新到高手,怎样快速掌握鸿蒙开发?[课程入口] 正文: 在应用开发时,我们常需要将一些数据缓存到本地,以提升用户体验.比如在一个电商的app中,如果希望用户登录成功后,下次打 ...

  2. Servlet数据缓存

    缓存是提高数据访问能力,降低服务器压力的一种必要的方式,今天我要说的数据缓存方式有两种,1-->session对单个数据访问接口页面的数据进行缓存,2-->单例模式对整个servlet页面 ...

  3. 利用js对象将iframe数据缓存, 实现子页面跳转后, 返回时不丢失之前填写的数据

    利用js对象将iframe数据缓存, 实现子页面跳转后, 返回时不丢失之前填写的数据 实现描述:将数据存放在js对象中, 然后放在父页面的document对象中, 在页面刷新的时候将父页面的值取出来, ...

  4. 第十七课:js数据缓存系统的原理

    这一章主要讲的是jQuery的缓存系统的历史发展,以及他自己的框架的缓存系统的实现.都是源码解析. 我就挑几个重点讲下: (1)jQuery的缓存机制的原理 jQuery的缓存机制实现的原理是在元素中 ...

  5. 腾讯面试题,js处理1千万条数据排序并且页面不卡顿

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. js/jquery控制页面动态加载数据 滑动滚动条自动加载事件--转他人的

    js/jquery控制页面动态加载数据 滑动滚动条自动加载事件--转他人的 相信很多人都见过瀑布流图片布局,那些图片是动态加载出来的,效果很好,对服务器的压力相对来说也小了很多 有手机的相信都见过这样 ...

  7. JS页面刷新保持数据不丢失

    转自:https://blog.csdn.net/qq_32439101/article/details/78134877 下面是 DOM Storage 的接口定义: interface Stora ...

  8. angular js 页面修改数据存入数据库

    一.编写service,修改数据要根据ID回显数据 //根据ID查询 public Brand findById(Long id); //修改 public int update(Brand bran ...

  9. jQuery数据缓存方案详解:$.data()的使用

    我们经常使用隐藏控件或者是js全局变量来临时存储数据,全局变量容易导致命名污染,隐藏控件导致经常读写dom浪费性能.jQuery提供了自己的数据缓存方案,能够达到和隐藏控件.全局变量相同的效果,但是j ...

随机推荐

  1. linux下快速列出局域网中所有主机名(计算机名)的脚本

    最近有列出局域网中所有主机名的需求(SMB协议里的),但是findsmb命令总是列不全,搜了搜网上也没什么现成的解决方案,于是自己写了个python脚本 脚本会扫描局域网arp表中所有ip,并尝试解析 ...

  2. 恕我直言,我也是才知道ElasticSearch条件更新是这么玩的

    背景 ElasticSearch 的使用度越来越普及了,很多公司都在使用.有做日志搜索的,有做商品搜索的,有做订单搜索的. 大部分使用场景都是通过程序定期去导入数据到 ElasticSearch 中, ...

  3. JPA第二天

    学于黑马和传智播客联合做的教学项目 感谢 黑马官网 传智播客官网 微信搜索"艺术行者",关注并回复关键词"springdata"获取视频和教程资料! b站在线视 ...

  4. MacOS下SpringBoot基础学习

    学于黑马和传智播客联合做的教学项目 感谢 黑马官网 传智播客官网 微信搜索"艺术行者",关注并回复关键词"springboot"获取视频和教程资料! b站在线视 ...

  5. bzoj 1738 [Usaco2005 mar]Ombrophobic Bovines 发抖的牛 最大流+二分

    题目要求所有牛都去避雨的最长时间最小. 显然需要二分 二分之后考虑如何判定. 显然每头牛都可以去某个地方 但是前提是最短路径<=mid. 依靠二分出来的东西建图.可以发现这是一个匹配问题 din ...

  6. 符合AUTOSAR(AP&CP)的嵌入式系统和软件设计工具

    AUTOSAR Builder功能介绍 AUTOSAR Builder 是达索旗下一种基于 Eclipse 的开放性.可扩展工具套件,用于设计和开发符合 AUTOSAR 标准的系统和软件.最新版本20 ...

  7. 你不是说你会Aop吗?

    一大早,小王就急匆匆的跑过来找我,说:周哥,那个记录日志的功能我想请教一下. 因为公司某个项目要跟别的平台做对接,我们这边需要给他们提供一套接口.昨天,我就将记录接口日志的工作安排给了小王. 下面是我 ...

  8. 打开桌面的Eclipse闪退,打不开

    参考了网上说的方法: .在C:/WINDOWS/system32 系统文件夹中ctrl+F 然后搜索java.exe,如果存在java.exe, javaw.exe etc.全部删除. 2.内存不足, ...

  9. 用 Python 制作关不掉的端午安康弹窗

    端午节又称端阳节.龙舟节.重午节.龙节.正阳节.天中节等,端午节源自天象崇拜,由上古时代祭龙演变而来,因传说战国时期的楚国诗人屈原在五月五日跳汨罗江自尽,后来人们亦将端午节作为纪念屈原的节日,在端午节 ...

  10. ECS7天实践进阶训练营Day2:基于阿里云ECS部署MediaWiki

    一.概述 MediaWiki是全球最著名的开源Wiki程序,运行于PHP+MySQL环境,MediaWiki从2002年被作为维基百科的系统软件,并由大量其他应用实例(例如萌娘百科),因此MediaW ...