废话
钟离镇楼!
其实本身觉得这个没什么可以单独拿出来的,只是最近有点闲。但是这个技巧又非常实用。
1、写这篇文章的原因是因为我发现大家对于状态管理的误解(正确的是叫做数据管理或者说是前端数据库管理)
2、看到掘金有人发老梗,利用axios优化接口请求,取消重复请求。其实有更好的办法。
取消接口重复请求实际上是项目上有时候非常好的优化方式,但是又非常不好。具体看文章,哈哈
一、数据缓存的类型
1、localStorage
大小5M,文件存储级别,不清理浏览器缓存不消失
2、sessionStorage
大小5M,内存级别,当前标签页关闭则丢失
3、Cookie
按4097字节算吧,前端可以操作(后端可以定义不可操作的数据),但是一般由后端定义,并且现在新版的浏览器在逐步的抛弃该功能
4、IndexedDB
最小250M,文件级别(支持事务,属于websql的替代品),需要清理浏览器缓存才可以。一般用不到,主要是因为浏览器不做客户端的话那么就没什么用。做本地客户端可以用,比如electron
5、内存存储
就是变量存储,可以说是没有上线,取决于你的内存
6、……
其他还有webSql之类的,很多方式。主流的就上面这些
二、我平常项目如何使用这些存储的
1、常用情况或者说早期
在前端还没有太发展起来之前,其实前端存储数据应该都是以内存存储为主要方式。但是内存存储就像sessionStorage一样,一刷新就没有了。
再后来浏览器除了cookie外,支持了sessionStorage、localStorage、websql等各种方式,前端才慢慢知道原来浏览器可以存储数据。这是前端面向客户端化的基础。
但是在很多前端初学者来说,都是直接拿着localStorage等api直接就上去怼。这个页面需要,我写一个,那个页面需要我写一个。项目越来越大,不知道哪里又写了一个。然后运行调试的时候发现把之前的存储给顶掉了。就像以前的var变量提升为全局变量一样,所以这样的前端是无法成为一个大项目的
2、从后端开发开发经历来思考前端存储(统一管理前端数据)
后端的存储其实比较好理解,内存存储,硬盘存储
然后转变为工具主要就是数据库,分为内存数据库和文件数据库。MySql属于文件数据库,redies属于内存级别。都是可查看,并且较为统一的。后端写数据之前都会先看数据库字段,然后再根据数据情况进行操作数据存储。但是前端那叫一个乱哦
那前端能不能也做一个统一的数据库呢?答案肯定是可以的
3、从现代化前端框架可以逆推前人项目(造轮子能力)
1、从react,vue框架上存储redux,vuex等等的前端状态管理,这是一个可聚合,可管理的js内存集合
ps:很多前端理解不够深刻的就把这当做状态管理了,吐槽那些不懂的管理层,前端和后端们。这难道不是天然的前端数据库吗
2、配合目前现有的插件,vuex持久化,redux持久化,这不就把状态库变成前端的数据库了么?
3、对项目进行约定规范
虽然解决了前端项目数据库的问题,但是需要有约定。约定大家在操作类似localStorage等api的时候不再可以直接写存储。必须接入vuex等能力,统一从vuex等状态库去操作数据。那么从数据存储的方面来看,就很清晰明了了。
4、逆推前人项目
关于redux和vuex等现代化框架来说,配合localStorage等持久化存储时非常方便的。但是没有redux和vuex呢?其实也很简单啊。
拿vuex来说,vuex是一个js文件,你定义这个js文件的数据存储的增删改查api,然后结合localStorage不就好了。
代码我就不写了,大神都懂,小白可以搜索《localStorage统一管理方案》。
vue项目vuex+vuex-persistedstate,所有数据操作走vuex
react项目redux+redux-persist,react方案特别多。vue走我上面推荐的就行了。
三、利用好变量,优化你的接口请求
重头戏来了,其实非常简单哦。
1、谈谈接口请求优化,取消重复请求
什么情况下会出现重复请求呢?
手抖了,不小心连续请求两次。老项目,有一个数据接口,比如分类接口,好多地方要用。
第一个情况其实应该用节流防抖等设计模式去解决。第二种呢?这不是异常,应该要这么做。
2、取消重复请求的缺点
如果是一个新项目,那么你需要的数据接口请求很少。自然也就不不太会发生这种情况。但是你一个老项目怎么办呢?
亲身举例:之前在云问做一个两年的老前端项目。也许初始项目很小,没有这些问题。但是随着项目越来越大,页面中存在几个基本数据获取接口。比如省市区,比如分类还有权限等等。之前同事“咔”一刀,利用axios中间拦截能力把重复请求的直接砍掉。好吗,项目多处直接功能瘫痪。无奈为了业务放弃性能优化。
3、利用前端数据库能力提前缓存好接口数据,存储在vuex等地方
这个想法非常好的,但是之前的人没用这一套,你接入这套管理方案的成本是至少三个js文件的改动级别。你怎么办呢?
4、巧妙利用js文件和声明变量
原理:js内存变量能力和js文件缓存能力
1、首先你声明的变量需要放在一个js文件中进行导出,你会发现你到处都可以获取到这个文件中存储的变量值。那你修改之后是不是也可以拿到修改之后的值呢?
2、把这种基础的短时间不会变化数据的接口数据,在请求之后把数据存入js文件的变量中,当重复请求的时候,判断变量是否有值,有就直接取值。那是不是接口下次请求进来就不会在走后台接口呢?
5、实践代码(项目中拎出来的代码)
这是我一个项目中的代码,其中有一个地方是一个级联组件。组件需要选择视频数据,剧本数据。级联组件使用的地方非常多。但是每次都加载组件都会导致接口请求数据,那么问题就大了。用户会觉得很卡。说实在产品都没想到,我自己加的功能。唉
代码为vue2代码方式
首先声明一个store.js文件
import Vue from 'vue'
const Store = Vue.observable({
AllVideo: new Map(), // 所有视频,性能优化, 存在数据情况这里取数据
AllDrama: new Map(), // 所有剧本,性能优化
})
const Mutations = {
// 重置数据
restData() {
Store.AllDrama = new Map()
Store.AllDrama = new Map()
},
}
export { Store, Mutations }
复制代码
在级联组件中导入函数
import { Store } from 'store'
复制代码
组件部分,干掉多余逻辑和处理,呈现一个较为简单的结构给大家
<script>
import { Store } from '../store'
export default {
data() {
return {}
},
methods: {
// 获取所有视频
async getAllVideo() {
try {
let materialType = this.materialType
materialType = materialType === 3 ? 2 : this.materialType
// 如果内存中存在数据则直接返回,不走接口请求数据
const typeData = Store.AllVideo.get(materialType)
if (typeData) return Promise.resolve(typeData)
// 请求接口
const result = await Service.VideoServer.videoList({
data: {
corpId: this.$store.state.userInfo.corpid,
filterStatus: [1],
page: 1,
size: 2000,
},
})
const records = result.data.records ?? []
//第一次请求的情况下同时把数据存入到js文件的变量中
Store.AllVideo.set(materialType, videoList)
return Promise.resolve(videoList)
} catch (e) {
return Promise.reject(e)
}
},
},
}
</script>
复制代码
6、注意事项
实际上就这么简单,页面上就很容易的把请求优化掉了。还不会产生全局不良影响。
注意点:主要就是这个属于你自己额外开辟的存储,属于内存存储,随着刷新就丢失。但是在不刷新页面的情况下存储会一直驻留在页面的内存中。注意使用,别引发内存泄露问题。