前端本地存储数据库存储之IndexedDB

news/2024/4/25 23:14:50/文章来源:https://blog.csdn.net/nihaio25/article/details/129197614

时隔两个月,再次挥笔写文章,这篇文章,两三个月都在公司写项目自研项目,其中觉得特别浏览器的缓存我都用便了,像localStorage,sessionStorage,cookie,IndexedDB都用过遍了。我用它们来做什么呢?下面我来简单的介绍一下它们,但这篇的文章的重点是IndexedDB。

介绍

1、cookie、localStorage和sessionStorage是什么?

1)cookie

  • cookie 是一个非常具体的东西,指的就是浏览器里面能永久存储的一种数据,仅仅是浏览器实现的一种数据存储功能。

  • cookie 由服务器生成,发送给浏览器,浏览器把 cookie 以kv的形式保存到某个目录下的文本文件内,下一次请求同一网站时会把该 cookie 发送给服务器。

  • cookie 的过期时间由客户端设置。若不设置过期时间,则表示这个 cookie 的生命期为浏览器会话期间,关闭浏览器窗口, cookie 就会消失。这种生命期为浏览器会话期的 cookie 被称为会话cookie。如果设置了过期时间,则在设置的 cookie 过期时间之前一直有效,即使窗口或浏览器关闭也会一直有效。

  • 会话cookie一般不存储在硬盘而是保存在内存里,当然这个行为并不是规范规定的。若设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再打开浏览器后这些 cookie 仍然有效直到超过设定的过期时间。对于保存在内存里的 cookie ,不同的浏览器有不同的处理方式。

  • 可用 document.cookie = “” 来设置 cookie 的值。cookie的值是键值对的形式存在,当设置的键一样时,会覆盖掉原先的值。当键不一样时,对进行叠加操作。这里附上一篇我看过觉得比较好理解的关于如何设置cookie的文章,大家可以根据自身需求进行查看~

2)localStorage

始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;
同源窗口都会共享,并且不会失效,不管窗口或者浏览器关闭与否都会始终生效。

3)sessionStorage

浏览器存储的一种形式。
仅在当前浏览器窗口关闭前有效,不可能持久保持。
在相同浏览器里,如果是在当前页面里面跳转进入一个新的页面,可以共享;而如果是直接打开一个新的页面,不能共享。

区别

HTML5中提出了webStorage的概念,webStorage包括sessionStoragelocalStorage,只为了保存数据,不会与服务器进行通信。
cookie,localStorage,sessionStorage都是在客户端(本地)保存数据,存储数据的类型:字符串
cookie会随着HTTP请求发送到服务器,webStorage不会随着HTTP发送到服务器端,所以安全性相对来说比cookie高,不必担心截获。
webStorage拥有更大的存储量,cookie大小限制4kb,webStorage达到5M或更大
webStorage拥有setItem,getItem,removeItem,clearapicookie需要自己封装
localStorage要手动清除,sessionStorage在浏览器关闭后清除。

生命周期

cookie :可设置失效时间,否则默认为关闭浏览器后消失
localStorage :除非被手动清除,否则永久保存
sessionStorage:仅在当前网页会话下有效,关闭页面或浏览器后就会被清除

进行一个简单的对比。

特性cookielocalStoragesessionStorageindexedDB
数据生命周期一般由服务器生成,可以设置过期时间除非被清理,否则一直存在页面关闭就清理除非被清理,否则一直存在
数据存储大小4K5M5M无限
与服务端通信每次都会携带在header中,对于请求性能有一定影响不参与不参与不参与

补充cookie 原本并不是用来储存的,而是用来与服务端通信的,需要存取请自行封装 api
localStorage 则自带 getItemsetItem 方法,使用很方便。

–关于它们的介绍我就摘抄就到这,详细的介绍对于他们的看着。
参考:
cooike的看这个
三者比较详细说明看这里

那我用它们的来干嘛了。

我对它们的用途

  1. cooike,用它做了登录状态的设定,本来是用 websocetk来搞的,发现它还需要从一个门户跳转到另一个门户,这时候就可以利用它的特性来做,token的共享。
    对于cookie是区分端口的,但是浏览器实现来说,cookie区分域,而不区分端口,也就是说,同一个ip下的多个端口下的cookie是共享的!ip相同,端口不同,覆盖。
  2. 对于sessionStorage,我们有这样的一个需求,就是一个地方只能一个账号登录,而且在当前的页面有效,哪这样的需求,就可以用sessionStorage来生产存储它的临时的uuid,在这个当前标志它的唯一性,凡是当前页面用到的它的可以都携带它。
  3. localStorage用来做存取用户公共不变的信息。
  4. 对于indexDB我用来做了图片的存储。

IndexDB存储图片做动画。(分享我解决这个问题的过程)

为啥用它来做呢,本来我打算localStorage来存储的,但是我发现localStorage容量只有5M,刚好五张图,刚好超出了它的存储空间。
当然图片这种小图没必要存,大图,存起来只为了更快的响应,提升用户的体验。为啥存储这图片,因为这是五张长图,用来做首页的动画效果,跟阿里云的图标的一样,不过它的是小图,我的是大图。所以需要一个存储。
对于这个动画效果,苦恼了我两天,实现这个动画并不难,但是高性能,让它正常运作就很难,首先图片,图片我想压缩一下,发现图片已经最小了(但还是差不多有1M),在压下去分辨率就很模糊了,那不行,必须清晰,如果采用链接的形式,去请求,太久了。那也不行。也会产生了,但图片加载了一半,动画会出现鬼畜现在。那也不行。
然后对于动画,是高性能消耗,阿里的是用js去实现的,但是我不想这样玩,就动态的给它添加类名,进行一个控制。那就要onMouseLeaveonMouseEnter来控制,对于这中高性能的千万不要用react的useState,去控制某个状态,最好是原生的js。
如果说图片问题,哪采用预加载提前去加载这张图片不就行了嘛,但是就会出现一个问题,每次路由跳转回来的时候就会出现资源销毁。然后每次都发起了请求,这种几张图就几个就请求了,一般来说图片会强制缓存,采用的预加载的方式能解决了,但是后端并不想参与这件事,我的路由采用的是懒加载的方式。然后我又想到了另外一种办法,你不是让它路由跳转页面不被销毁,Vue keepalive,很不辛我用的react,那好啊,找插件,会着自己写个组件啊(自己写个是不可能的,对于摸鱼人来说),那很好,那就用插件,然后我发现会出现了一种情况,它把动画的状态都缓存了,每次路由跳转回来都会有动画效果,没有回归到初始的位置。所以这种方案又不可行。
最后采用了存取图片的方法,把图片的url的地址转为base64进行一个存储,使用到canvas,进行一个转化。然后保存到IndexDB(对于这个方法来说,base64会比原图还大一倍,但是不影响啊,它只有第一次会卡一下,让下载完在进行一个读取)。
然后效果出来了,但是每次跳出去,跳回来都会有白屏的效果,然后项目负责人说,还是不行,达美,没办法还得在想办法解决这个问题,是什么产生了这个问题呢。进行一个debug,发现是base64图片的资源太大了,react的一个影响了渲染机制需要的一个时间过渡。这个时间过渡,那这个过渡时间用什么来代替呢,然后我想到了,把长图的第一帧拿出来,只有个十几KB,这样但base64图片还没过来的时候,用这张图进行一个暂时的替代,然后当base64图片加载过来才赋予它一个动画效果。然后效果差不多了。但是还没完,进去的还没加载出来动画,在离开的时候赋予了离开的动画,那怎办,加一个判断就好了,进行一个判断是否有进去的动画的类。最后完美解决。

关键代码就几行,因为保密的原因图片跟其它的代码不能截图。

//离开的时候赋予离开的动画。并且进行一个判断是否有进去的动画。const handelMouseLeave = (className, entery, leave) => {let e = document.getElementsByClassName(className)[0]let temp = e.style.backgroundImageif(temp.includes('data:image/png')&& e.classList.contains(entery)){e.classList.add(leave)e.classList.remove(entery)}
}
//进行的时候赋予进去的动画。
const handelMouseEnter = (className, entery, leave) => {let e = document.getElementsByClassName(className)[0]let temp = e.style.backgroundImageif(temp.includes('data:image/png')){e.classList.add(entery)e.classList.remove(leave)}
}

关键代码很简单,都是原生的一个操作,很简单。
这是我解决怎么一个问题的思路分享给大家,有些地方可能我没考虑到。可能解决问题的过程中疏忽了一些事。把事情搞复杂了,但总算解决了。下面就进行今天的重点主题,IndexDB。

IndexedDB

MDN官网是这样解释Indexed DB的:

IndexedDB 是一种底层 API,用于在客户端存储大量的结构化数据(也包括文件/二进制大型对象(blobs))。该 API 使用索引实现对数据的高性能搜索。虽然 Web Storage 在存储较少量的数据很有用,但对于存储更大量的结构化数据来说力不从心。而 IndexedDB 提供了这种场景的解决方案。

官网上的这句话也很简单明了,意思就是IndexedDB主要用来客户端存储大量数据而生的,我们都知道cookie、localstorage等存储方式都有存储大小限制。如果数据量很大,且都需要客户端存储时,那么就可以使用IndexedDB数据库。

对于同步还是异步MDN官网怎么说的

使用 IndexedDB 执行的操作是异步执行的,以免阻塞应用程序。IndexedDB 最初包括同步和异步 API。同步 API 仅用于 Web Workers,且已从规范中移除,因为尚不清晰是否需要。但如果 Web 开发人员有足够的需求,可以重新引入同步 API。
这种概念性的东西还是去官网了解吧,今天要分享的是对它进行的一个操作的代码的封装。

const DBVersion = 1;//版本更新
export const mainStore = 'filesImg'

打开数据库(数据库名,和版本号为1)

export function openDB(dbName) {//返回一个 promise对象,为了实现异步传输(创建promise对象后就会立即执行)return new Promise((resolve, reject) => {//兼容浏览器var indexedDB =window.indexedDB ||window.mozIndexedDB ||window.webkitIndexedDB ||window.msIndexedDB;let db, ObjectStore;//打开数据库,若没有就创建const request = indexedDB.open(dbName, DBVersion);//调用数据库打开或创建成功回调函数()request.onsuccess = (event) => {//获取 数据库对象,里面有很多方法(增删改查)db = event.target.result;// console.log('数据库打开成功!');//返回数据库对象resolve(db)};//创建或打开数据库失败回调函数request.onerror = (event) => {console.error("本地储存库打开错误");reject(event);};//数据库更新回调函数。初次创建,后续升级数据库用request.onupgradeneeded = (event) => {// console.log('数据库更新啦');//获取数据库对象db = event.target.result;// 清除旧 objectStore(对旧 objectStore 的数据进行迁移,暂未)if (db.objectStoreNames.contains(mainStore)) {// console.log(db.objectStoreNames); DOMStringList 对象db.deleteObjectStore(mainStore);}//创建新存储库(存储库名称,对象)-创建表(users表)ObjectStore = db.createObjectStore(mainStore, {//主键,必须唯一KeyPath: "fileID",autoIncrement: true   //实现自增加});//创建索引,在后面查询数据的时候可以根据索引查-创建字段(字段名,索引名,是否唯一:true)//可以通过索引来查询ObjectStore.createIndex('getImg', ['imgId','name']);}})
}

插入数据(数据库对象,表名,插入的数据通常为对象)

export function addData(db, storeName, data) {var request = db// 事务对象 指定表格名称和操作模式("只读""读写").transaction([storeName], "readwrite")// 仓库对象.objectStore(storeName).add(data);//成功回调函数request.onsuccess = function (event) {// console.log("数据写入成功");};//失败回调函数request.onerror = function (event) {console.error("数据写入失败");};
}

通过主键查询数据(数据库对象,表名,主键值)

export function getDataByKey(db, storeName, key) {return new Promise((resolve, reject) => {var transaction = db.transaction([storeName]); // 事务var objectStore = transaction.objectStore(storeName); // 仓库对象var request = objectStore.get(key); // 通过主键获取的查询数据//失败回调函数request.onerror = function (event) {console.log("事务失败");};//查询成功回调函数request.onsuccess = function (event) {// console.log("主键查询结果: ", request.result);//返回值对应的值resolve(request.result);};});
}

通过游标查询所有数据(数据库对象,表名)

export function cursorGetData(db, storeName) {let list = [];var store = db.transaction(storeName, "readwrite") // 事务.objectStore(storeName); // 仓库对象//初始化了一个游标对象(指针对象)var request = store.openCursor();//成功回调函数, 游标开启成功,逐行读数据request.onsuccess = function (e) {var cursor = e.target.result;if (cursor) {// 将查询值添加到列表中(游标.value=获取值)list.push(cursor.value);cursor.continue(); // 遍历了存储对象中的所有内容} else {// console.log("游标读取的数据:", list);//返回数据// resolve(list);}};
}

通过索引查询,查询满足相等条件的第一条数据(数据库对象,表名,索引名字,索引值)

export function getDataByIndex(db, storeName, indexName, indexValue) {//通过Promise实现异步回调return new Promise((resolve, reject) => {var store = db.transaction(storeName, "readwrite").objectStore(storeName);var request = store.index(indexName).get(indexValue);//查询失败回调函数request.onerror = function () {console.log("查询失败");};//查询成功回调函数request.onsuccess = function (e) {var result = e.target.result;// console.log(typeof (result));//返回成功查询数据resolve(result)}});
}

通过索引和游标查询多条匹配的数据(数据库对象,表名,索引名,索引值)

export function cursorGetDataByIndex(db, storeName, indexName, indexValue) {return new Promise((resolve, reject) => {let list = [];var store = db.transaction(storeName, "readwrite").objectStore(storeName); // 仓库对象var request = store.index(indexName) // 索引对象.openCursor(IDBKeyRange.only(indexValue)); // 指针对象request.onsuccess = function (e) {var cursor = e.target.result;if (cursor) {// 必须要检查list.push(cursor.value);cursor.continue(); // 遍历了存储对象中的所有内容} else {// console.log("游标索引查询结果:", list);resolve(list)}};request.onerror = function (e) {console.log('search error');};})
}

通过提供的主键值来更新数据,如果主键值不存在,就添加数据(数据库对象,表名,新的数据值)

export function updateDB(db, storeName, data) {return new Promise((resolve, reject) => {alert('err')var request = db.transaction([storeName], "readwrite") // 事务对象.objectStore(storeName) // 仓库对象.put(data);request.onsuccess = function () {// console.log("数据更新成功");resolve('数据更新成功')};request.onerror = function () {// console.log("数据更新失败");reject('数据更新失败')};})
}

通过主键删除数据(数据库对象,表名,主键值)

export function deleteDB(db, storeName, id) {return new Promise((resolve, reject) => {var request = db.transaction([storeName], "readwrite").objectStore(storeName).delete(id);request.onsuccess = function () {// console.log("数据删除成功");resolve('删除成功!')};request.onerror = function () {// console.log("数据删除失败");reject('删除失败')};})
}

通过游标和索引删除指定的多条数据(数据库对象,表名,索引名,索引值)

export function cursorDelete(db, storeName, indexName, indexValue) {return new Promise((resolve, reject) => {var store = db.transaction(storeName, "readwrite").objectStore(storeName);var request = store.index(indexName) // 索引对象.openCursor(IDBKeyRange.only(indexValue)); // 指针对象request.onsuccess = function (e) {var cursor = e.target.result;var deleteRequest;if (cursor) {deleteRequest = cursor.delete(); // 请求删除当前项deleteRequest.onerror = function () {// console.log("游标删除该记录失败");reject('删除失败!')};deleteRequest.onsuccess = function () {// console.log("游标删除该记录成功");resolve('删除成功!')};cursor.continue();}};request.onerror = function (e) { };})
}

关闭数据库

export function closeDB(db) {return new Promise((resolve, reject) => {db.close();resolve('数据库已关闭')})
}

IndexedDB数据库没有我们想象的那么复杂,了解了它的几个基本概念,上手还是很快的,无非就是增删改查等等,虽然可能开发中用的少,但是了解一下不至于真正用到的时候两眼抓瞎。

MDN:IndexedDB
参考:indexDB

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_73916.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

五种IO模型以及select多路转接IO模型

目录 一、典型IO模型 1.1 阻塞IO 1.2 非阻塞IO 1.3 信号驱动I0 1.4 IO多路转接 1.5 异步IO 多路转接的作用和意义 二、多路转接IO模型(select) 2.1 接口 2.2 接口当中的事件集合: fd_set 2.2 select使用事件集合(位图&am…

174万亿采购,奔向数字化

采购不单纯发生在外部,更发生在内部,只有两者同时进行,才能完成采购中心从成本到利润中心角色的转变。 作者|斗斗 编辑|皮爷 出品|产业家 数字化,让很多企业业务流程发生了质变。 《2022数字化采购发展报告》显示&#x…

破解票房之谜:为何高票房电影绕不过“猫眼们”?

如此火爆的春节档很多,如此毁誉参半的春节档鲜有。2023开年,集齐张艺谋、沈腾的《满江红》,以及有票房前作打底的《流浪地球2》接连两部春节档电影票房进入前十,为有些颓靡的中国电影市场注入了一针“强心剂”。与票房同样热闹起来…

无重叠区间-力扣435-java贪心策略

一、题目描述给定一个区间的集合 intervals ,其中 intervals[i] [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠 。示例 1:输入: intervals [[1,2],[2,3],[3,4],[1,3]]输出: 1解释: 移除 [1,3] 后,剩下的区间没有重叠。…

【爬虫】2.2 BeautifulSoup 装载HTML文档

HTML文档结点的查找工具很多,其中 BeautifulSoup 是功能强大且十分流行的查找工具之一。1. BeautifulSoup 的安装安装:pip install bs4导包:from bs4 import BeautifulSoup2. BeautifulSoup 装载HTML文档如果 doc 是一个 HTML 文档&#xff0…

深度学习训练营之yolov5 官方代码调用以及-requirements.txt下载当中遇到的问题

深度学习训练营之yolov5 官方代码调用原文链接内容总结环境介绍前置工作简单介绍yolov5下载源码yolov5的下载遇到问题问题解析问题处理创建虚拟环境下载当中遇到的问题代码运行视频检测参考内容原文链接 🍨 本文为🔗365天深度学习训练营 中的学习记录博客…

gazebo仿真环境中添加robotiq 2f 140的gripper_controller控制器

gazebo仿真环境中添加robotiq 2f 140的gripper_controller控制器 搭建环境: ubuntu: 20.04 ros: Nonetic sensor: robotiq_ft300 gripper: robotiq_2f_140_gripper UR: UR3 reasense: D435i 通过下面几篇博客配置好了ur3、力传感器、robotiq夹爪、rea…

18523-47-2,3-Azidopropionic Acid,叠氮基丙酸,可以与炔烃发生点击化学反应

【中文名称】3-叠氮基丙酸【英文名称】 3-Azidopropionic Acid,3-Azidopropionic COOH【结 构 式】【CAS】18523-47-2【分子式】C3H5N3O2【分子量】115.09【纯度标准】95%【包装规格】1g,5g,10g【是否接受定制】可进行定制,定制时…

java原理4:java的io网络模型

文章目录1:基础概念1:同步和异步2:阻塞和非阻塞2.1:阻塞IO2.2:非阻塞io2.3:io复用3:同步/异步和阻塞/非阻塞3.1:同步非阻塞NIO4: redis为什么速度快Java 网络IO模型简介1&#xff1a…

Tapdata 和 Databend 数仓数据同步实战

作者:韩山杰https://github.com/hantmacDatabend Cloud 研发工程师基础架构在云计算时代也发生着翻天地覆的变化,对于业务的支持变成了如何能利用好云资源实现降本增效,同时更好的支撑业务也成为新时代技术人员的挑战。 本篇文章通过&#xf…

删除MySQL表中的重复数据?

前言 一般我们将数据存储在MySQL数据库中,它允许我们存储重复的数据。但是往往重复的数据是作废的、没有用的数据,那么通常我们会使用数据库的唯一索引 unique 键作为限制。问题来了啊,我还没有创建唯一索引捏,数据就重复了&…

jianzhiOffer第二版难重点记录

04. 二维数组中的查找https://leetcode.cn/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/ 思路:可以每层用以恶搞二分查找,优化思路:从左下角出发直接用二分。 ​​​​​​07. 重建二叉树https://leetcode.cn/problems/zhong-jian-er-cha…

springboot+vue.js高校大学生选课成绩管理系统javaweb

本课题要求实现一套学生成绩管理系统,系统主要包括管理员,学生和教师三大模块 (a) 管理员;管理员进入系统主要功能包括首页,个人中心,教师管理,学生管理,公告信息管理,课程类型管理&…

Android自定义View实现横向的双水波纹进度条

效果图:网上垂直的水波纹进度条很多,但横向的很少,将垂直的水波纹改为水平的还遇到了些麻烦,现在完善后发布出来,希望遇到的人少躺点坑。思路分析整体效果可分为三个,绘制圆角背景和圆角矩形,绘…

Linux学习(7.5)linux目录配置与重点回顾

鸟哥的 Linux 私房菜 -- Linux 的文件权限与目录配置 (vbird.org) 怎么记啊,直接点进去看吧 目录 Linux目录配置的依据--FHS 绝对路径与相对路径 重点回顾 以下内容转载自鸟哥的Linux私房菜 Linux目录配置的依据--FHS 是希望让使用者可以了解到已安装软件通常…

16、变量、流程控制与游标

文章目录1 变量1.1 系统变量1.1.1 系统变量分类1.1.2 查看系统变量1.2 用户变量1.2.1 用户变量分类1.2.2 会话用户变量1.2.3 局部变量1.2.4 对比会话用户变量与局部变量2 定义条件与处理程序2.1 案例分析2.2 定义条件2.3 定义处理程序2.4 案例解决3 流程控制3.1 分支结构之 IF3…

嵌入式系统硬件设计与实践(学习方法)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 刚读书的时候,对什么是嵌入式,其实并不太清楚。等到自己知道的时候,已经毕业很多年了。另外对于计算机毕业的学…

Python近红外光谱分析与机器学习、深度学习方法融合实践技术

、 第一n入门基础【理论讲解与案 1、Python环境搭建( 下载、安装与版本选择)。 2、如何选择Python编辑器?(IDLE、Notepad、PyCharm、Jupyter…) 3、Python基础(数据类型和变量、字符串和编码、list和tu…

每日学术速递2.24

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.LG 1.BUAA_BIGSCity: Spatial-Temporal Graph Neural Network for Wind Power Forecasting in Baidu KDD CUP 2022 标题:BUAA_BIGSCity:百度KDD CUP 2022风电预测…

新C++(10):Map\Set的封装

"湖人总冠军"一、Map\Set的介绍Set是C标准库中的一种关联容器。所谓关联容器就是通过键(key)来读取和修改元素。与map关联容器不同,它只是单纯键的集合。取自这里Map是STL 的一个关联容器,它提供一对一(其中…