思索-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 的值就可以了。
思索-js 页面ID识别及数据缓存的更多相关文章
- 从微信小程序到鸿蒙js开发【12】——storage缓存&自动登录
鸿蒙入门指南,小白速来!从萌新到高手,怎样快速掌握鸿蒙开发?[课程入口] 正文: 在应用开发时,我们常需要将一些数据缓存到本地,以提升用户体验.比如在一个电商的app中,如果希望用户登录成功后,下次打 ...
- Servlet数据缓存
缓存是提高数据访问能力,降低服务器压力的一种必要的方式,今天我要说的数据缓存方式有两种,1-->session对单个数据访问接口页面的数据进行缓存,2-->单例模式对整个servlet页面 ...
- 利用js对象将iframe数据缓存, 实现子页面跳转后, 返回时不丢失之前填写的数据
利用js对象将iframe数据缓存, 实现子页面跳转后, 返回时不丢失之前填写的数据 实现描述:将数据存放在js对象中, 然后放在父页面的document对象中, 在页面刷新的时候将父页面的值取出来, ...
- 第十七课:js数据缓存系统的原理
这一章主要讲的是jQuery的缓存系统的历史发展,以及他自己的框架的缓存系统的实现.都是源码解析. 我就挑几个重点讲下: (1)jQuery的缓存机制的原理 jQuery的缓存机制实现的原理是在元素中 ...
- 腾讯面试题,js处理1千万条数据排序并且页面不卡顿
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- js/jquery控制页面动态加载数据 滑动滚动条自动加载事件--转他人的
js/jquery控制页面动态加载数据 滑动滚动条自动加载事件--转他人的 相信很多人都见过瀑布流图片布局,那些图片是动态加载出来的,效果很好,对服务器的压力相对来说也小了很多 有手机的相信都见过这样 ...
- JS页面刷新保持数据不丢失
转自:https://blog.csdn.net/qq_32439101/article/details/78134877 下面是 DOM Storage 的接口定义: interface Stora ...
- angular js 页面修改数据存入数据库
一.编写service,修改数据要根据ID回显数据 //根据ID查询 public Brand findById(Long id); //修改 public int update(Brand bran ...
- jQuery数据缓存方案详解:$.data()的使用
我们经常使用隐藏控件或者是js全局变量来临时存储数据,全局变量容易导致命名污染,隐藏控件导致经常读写dom浪费性能.jQuery提供了自己的数据缓存方案,能够达到和隐藏控件.全局变量相同的效果,但是j ...
随机推荐
- Python操作adb命令脚本
一.脚本代码(有错误,抓紧改进中) import os import datetime date1=datetime.datetime.now().strftime('%Y%m%d') date2=d ...
- API返回延迟,FPM重启后恢复之后又重现 问题解决方案
背景 最近在提供后台API时,提供了一个简单逻辑的接口 部署在测试环境,自测没问题,提交测试 突然有一天,接口响应延迟严重,几乎每次都是3-4秒返回 这对于一个接口来说,肯定是有问题的 于是便有了以下 ...
- 【前端】H5,底边按钮吸边,但是覆盖了列表循环的内容
我的说情况大致类似于: PS:因为底边那个模块 绝对是浮动的,所有会遮住列表最下面一条现实的一部分, 解决:这个时候把body的底边的内边距调整到可显示的就可以了: body { background ...
- Sharding-JDBC实现读写分离
参考资料:猿天地 https://mp.weixin.qq.com/s/kp2lJHpTMz4bDWkJYjVbOQ 作者:尹吉欢 技术选型:SpringBoot + Sharding-JDBC ...
- vmware15虚拟机安装教程
自己碰到的问题:本人win7 64位旗舰版系统.之前用VMware12pro版本的软件,在安装Ubuntu18.04之后,有时候开启Ubuntu虚拟机时有点问题,重启就可以了.但是不稳定,所以改用VM ...
- SSH整合-hibernate
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property& ...
- LeetCode 89,因为题目晦涩而被点了1500+反对的搜索问题
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是LeetCode专题第55篇文章,我们一起来看看LeetCode中的第89题 Gray Code(格雷码). 这题的官方难度是Medi ...
- Chrome划词翻译-Saladict
Saladict 沙拉查词是一款专业划词翻译扩展,为交叉阅读而生.大量权威词典涵盖中英日韩法德西语,支持复杂的 划词操作.网页翻译.生词本.PDF,以及 Vimium 全键盘操作 . 迄今为止最好用的 ...
- Python | 面试的常客,经典的生产消费者模式
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是Python专题的第23篇文章,我们来聊聊关于多线程的一个经典设计模式. 在之前的文章当中我们曾经说道,在多线程并发的场景当中,如果我 ...
- SpringCloud微服务:基于Nacos组件,整合Dubbo框架
源码地址:GitHub·点这里 || GitEE·点这里 一.基础组件简介 1.Dubbo框架 Dubbo服务化治理的核心框架,之前几年在国内被广泛使用,后续由于微服务的架构的崛起,更多的公司转向微服 ...