前端存储方案

如今主流的存储方案:

  • cookie
  • web storage
  • indexDB

这三个浏览器兼容性最高的三种前端储存方案

1、cookie

它的出现是为了解决 HTTP 协议无状态特性的问题,简单来说就是想要得到上次http请求的数据是办不到的,只有再次从新请求。我们见得最多的应该就是登录态的长久保持。

虽然 Cookie 在部分领域仍有不可替代的价值,但其已经不再适合被做为一个前端本地储存方案去使用:

  • Cookie 在每次请求中都会被发送,如果不使用 HTTPS 并对其加密,其保存的信息很容易被窃取,导致安全风险
  • cookie在每次请求时都会自动写入到请求头内,会增加带宽占用,但其实放在今天的网络环境来看,这点占用基本可以忽略不计
  • Cookie 只允许储存 4kb 的数据

假设 abc.com 和 xyz.com 都内嵌了淘宝的广告,你会发现即使 abc.com 和 xyz.com 所有者不一致,两个网站上淘宝广告推荐的商品也出奇的一致,这背后是因为淘宝知道是同一个人,分别在 abc.com 和 xyz.com 访问淘宝的广告

这是如何实现的呢?答案是第三方 Cookie

它是如何工作的呢?

  1. 当用户处于 abc.com 时,浏览器会向 taobao.com/some-ads 发起一个 HTTP 请求
  2. 当淘宝服务器返回广告内容时,会顺带一个 Set-Cookie 的 HTTP 请求头,告诉浏览器设置一个源为 taobao.com 的 Cookie,里面存上当前用户的 ID 等信息
  3. 这个 Cookie 相对于 abc.com 而言就是第三方 Cookie,因为它属于 taobao.com
  4. 而当用户访问 xyz.com 时,由于 xyz.com 上也嵌入了淘宝的广告,因此用户的浏览器也会向 taobao.com/some-ads 发起请求
  5. 有意思的来了,发请求时,浏览器发现本地已有 taobao.com 的 Cookie(此前访问 abc.com 时设置的),因此,浏览器会将这个 Cookie 发送过去
  6. 淘宝服务器根据发过来的 Cookie,发现当前访问 xyz.com 的用户和之前访问 abc.com 的用户是同一个,因此会返回相同的广告

广告商用第三方 Cookie 来跨站定位用户大概就是这么个过程,实际肯定要复杂许多,但基本原理是一致的。

补充:浏览器在发送请求时何时会自动带上cookie

Set-Cookie响应头字段(Response header)是服务器发送到浏览器或者其他客户端的一些信息,一般用于登陆成功的情况下返回给客户端的凭证信息,然后下次请求时会带上这个cookie,这样服务器端就能知道是来自哪个用户的请求了。

Cookie请求头字段是客户端发送请求到服务器端时发送的信息(满足一定条件下浏览器自动完成,无需前端代码辅助)。

拿一个Http POST请求来说 http://aaa.www.com/xxxxx/list

如果满足下面几个条件:

1、浏览器端某个Cookie的domain字段等于aaa.www.com或者www.com

2、都是http或者https,或者不同的情况下Secure属性为false

3、要发送请求的路径,即上面的xxxxx跟浏览器端Cookie的path属性必须一致,或者是浏览器端Cookie的path的子目录,比如浏览器端Cookie的path为/test,那么xxxxxxx必须为/test或者/test/xxxx等子目录才可以

上面3个条件必须同时满足,否则该Post请求就不能自动带上浏览器端已存在的Cookie

HttpOnly 则用来禁止使用 JS 访问 cookie,很好的可以防止xss攻击。

2、Web Storage

HTML5 标准中,新增了一个 Web Storage 的本地储存方案,其包括

  • LocalStorage
  • SessionStorag

两者用法一致,相比于cookie,存储容量增加到了5M之多;区别点:

  • localstorage是持久化存储,除非自己手动删除,关闭浏览器后依然存在;而sessionstorage关闭浏览器后自动删除。
  • localstorage作用范围是整个浏览器,简单来说只要是用同一个浏览器打开的不同窗口还是不同网页之间都能够共享数据;而sessionstorage只能在同一个窗口下共享数据。

这里主要以 LocalStorage 为例进行介绍

主要特点:

  • 使用 Key-Value 形式储存
  • 使用很方便
  • Key 和 Value 以字符串形式储存

使用方法:

localStorage.setItem("键","值")//存值
localStorage.getItem("键") //取值
localStorage.removeItem("键")//删除某个值
localStorage.clear()//清空所有


缺点:

只能存入字符串数据类型,无法直接存对象......

举个🌰

localStorage.setItem('key', {name: 'value'});
console.log(localStorage.getItem('key')); // '[object, Object]'localStorage.setItem('key', 1);
console.log(localStorage.getItem('key')); // '1'

你会发现,存进去的如果是对象,拿出来就变成了字串‘[Object,object]’数据丢失了!

存进去的如果是 number,拿出来也变成了 string

要解决这个问题,一般是使用 JSON.stringify() 配合 JSON.parse()。

但是,这么做有一个缺点,那就是 JSON.stringify() 本身是存在一些问题的

🌰

const a = JSON.stringify({a: undefined,b: function(){},c: /abc/,d: new Date()
});
console.log(a) // "{"c":{},"d":"2022-02-02T19:40:12.346Z"}"
console.log(JSON.parse(a)) // {c: {}, d: "2022-02-02T19:40:12.346Z"}

如上,JSON.stringify() 无法正确转换 JS 的部分属性

  • undefiend
  • Function
  • RegExp(正则表达式,转换后变成了空对象)
  • Date(转换后变成了字符串,而非 Date 类的对象)

其实还有个 Symbol 也无法被转换,但由于 Symbol 本身定义(全局唯一性)就决定了,它不应该被转换,否则即使转换回来,也不会是原来那个 Symbol

Function 也比较特殊,不过要兼容的话,可以先调用 .toString() 转换为字符串储存,需要的时候再 eval 转回来

3、indexedDB

IndexedDB 的全称是 Indexed Database,从名字中就可以看出,它是一个数据库

IndexedDB 早在 2009 年就有了第一次提案,但其实它和 Web Storage 几乎是同一时间普及到各大浏览器的。IndexedDB 是一个正经的数据库,它在问世后替代了原来不正经的 Web SQL 方案,成为了当今唯一运行在浏览器里的数据库

在我看来,IndexedDB 其实更适合当作终极前端本地数据储存方案

相比于 LocalStorage,IndexedDB 的优点

  • 储存量理论上没有上限
    • Chrome 对 IndexedDB 储存空间限制的定义是:硬盘可用空间的三分之一
  • 所有操作都是异步的,相比 LocalStorage 同步操作性能更高,尤其是数据量较大时
  • 原生支持储存 JS 的对象
  • 是个正经的数据库,意味着数据库能干的事它都能干

但是缺点也比较致命:

  • 操作非常繁琐
  • 本身有一定门槛(需要你懂数据库的概念)

对于简单的数据储存而言,IndexedDB 的 API 显得太复杂了,再加上其 API 全是异步的,会带来额外的心智负担,远没有 LocalStorage 简单两行代码搞定数据存取来的快

因此,IndexedDB 在今天的使用规模相比 LocalStorage 差远了,即使 IndexedDB 本身的设计其实更适合用来在浏览器上储存数据

总之,如果不考虑 IndexedDB 的操作难度,其作为一个前端本地储存方案其实是接近完美的

indexedDB的使用

详细文档 IndexedDB API - JavaScript 教程 - 网道

使用 IndexedDB 的第一步是打开数据库:

const version = 1;
const request = window.indexedDB.open('studentdb',version);

上面这个操作打开了名为 studentdb 的数据库,如果不存在,浏览器会自动创建。IndexedDB 有一个版本(version)的概念,连接数据库时就可以指定版本。

然后 request 上有四个事件:

var db; // 全局 IndexedDB 数据库实例request.onupgradeneeded = function (event) {db = event.target.result;//得到实例console.log('version change');
};request.onsuccess = function (event) {db = request..target.result;console.log('db connected');
};request.onblocked = function (event) {console.log('db request blocked!')
}request.onerror = function (event) {console.log('error!');
};

触发事件时机:

  • onupgradeneeded 在版本改变时触发
    • 注意首次连接数据库时,版本从 0 变成 1,因此也会触发,且先于 onsuccess
  • onsuccess 在连接成功后触发
  • onerror 在连接失败时触发
  • onblocked 在连接被阻止的时候触发,比如打开版本低于当前存在的版本

注意这四个事件都是异步的,意味着在连接 IndexedDB 的请求发出去后,需要过一段时间才能连上数据库,并进行操作

开发者对数据库的所有操作,都得放在异步连上数据库之后,这有的时候会带来很大的不便。

新建表

新建数据库与打开数据库是同一个操作。如果指定的数据库不存在,就会新建。不同之处在于,后续的操作主要在upgradeneeded事件的监听函数里面完成,因为这时版本从无到有,所以会触发这个事件。

通常,新建数据库以后,第一件事是新建对象仓库 ObjectStore(即新建表)。

request.onupgradeneeded = function(event) {db = event.target.result;var objectStore = db.createObjectStore('person', { keyPath: 'id',autoIncrement: true // 自增整数  });
}

其中person为表名,id为你设置的表的主键。
更好的写法是先判断一下,这张表格是否存在,如果不存在再新建。

if (!db.objectStoreNames.contains('person')) {objectStore = db.createObjectStore('person', { keyPath: 'id' });
}


新建对象仓库以后,下一步可以新建索引。

request.onupgradeneeded = function(event) {db = event.target.result;var objectStore = db.createObjectStore('person', { keyPath: 'id' });objectStore.createIndex('name', 'name', { unique: false });objectStore.createIndex('email', 'email', { unique: true });
}

上面代码中,IDBObject.createIndex()的三个参数分别为索引名称、索引所在的属性、配置对象(说明该属性是否包含重复的值)。

添加数据

db.transaction('person', 'readwrite').objectStore('person').add({ id: 1, name: '张三', age: 24, email: 'zhangsan@example.com' });

写入数据需要新建一个事务。新建时必须指定表格名称和操作模式(“只读”或“读写”)。新建事务以后,通过IDBTransaction.objectStore(name)方法,拿到 IDBObjectStore 对象,再通过表格对象的add()方法,向表格写入一条记录。

数据形式如图所示:

直接添加数据,未添加索引

添加了索引

获取数据

如果要获取数据,需要一个 readonly 的 Transaction

const request = db.transaction('person', 'readonly').objectStore(person).get(2);

objectStore.get()方法用于读取数据,参数是主键的值。

读写操作是一个异步操作,通过监听事物对象的success事件和error事件,了解是否写入成功。

request.onsuccess = function (event) {console.log('数据写入/读取成功');
};request.onerror = function (event) {console.log('数据写入/读取失败');
}

遍历数据表

遍历数据表格的所有记录,要使用指针对象 IDBCursor。

objectStore.openCursor().onsuccess = function (event) {var cursor = event.target.result;if (cursor) {console.log('Id: ' + cursor.key);console.log('Name: ' + cursor.value.name);cursor.continue();} else {console.log('没有更多数据了!');}
};

新建指针对象的openCursor()方法是一个异步操作,所以要监听success事件。

更新和删除数据

var request = db.transaction(['person'], 'readwrite')//更新
request.objectStore('person').put({ id: 1, name: '李四', age: 35, email: 'lisi@example.com' });
//删除
request.objectStore('person').delete(1);

使用索引

索引的意义在于,可以让你搜索任意字段,也就是说从任意字段拿到数据记录。如果不建立索引,默认只能搜索主键(即从主键取值)。

即查找person表中索引name中名为张三的数据

var request = db.transaction(['person'], 'readwrite').objectStore('person').index('name').get('张三')

以上就是indexedDB的基本操作,更多说明查看文档。

综上,哪怕只是想简单的往 IndexedDB 里增加和查询数据,都需要写一大堆代码,操作非常繁琐,一不小心还容易掉坑里

4、GoDB.js

GoDB.js 是一个基于 IndexedDB 实现前端本地储存的类库

帮你做到代码更简洁的同时,更好的发挥 IndexedDB 的实力

首先安装:

npm install godb

对 IndexedDB 的增删改查,一行代码就可以搞定!

import GoDB from 'godb';const testDB = new GoDB('testDB'); // 连接数据库
const user = testDB.table('user'); // 获取数据表const data = { name: 'luke', age: 22 }; // 随便定义一个对象user.add(data) // 增.then(luke => user.get(luke.id)) // 查.then(luke => user.put({ ...luke, age: 23 })) // 改.then(luke => user.delete(luke.id)); // 删

可以参考 GoDB 的项目官网:https://godb-js.github.io/

5、localForage(推荐)

这是目前对indexedDB封装中最火热的类库,目前在github上的 star已经23.3k了。

它不仅极大的降低了用户心智负担,还具有良好的兼容性。而且他还有一个优雅降级策略,若浏览器不支持 IndexedDB 则使用 WebSQL ,如果不支持 WebSQL 则使用 localStorage,在所有主流浏览器中都可用。

另外能存储多种类型的数据,支持es6的 Promises API,而且支持添加回调函数。

localForage的使用

下载

npm install localforage

创建一个indexedDB

const myIndexedDB = localforage.createInstance({name: 'myIndexedDB',})

数据存取

由于indexedDB的存取都是异步的,建议使用 promise.then() 或 async/await 去读值

//存值
myIndexedDB.setItem(key, value)//取值
myIndexedDB.getItem('somekey').then(function (value) {// we got our value
}).catch(function (err) {// we got an error
});
orconst value = await myIndexedDB.getItem('somekey');

其他常用方法:

  • removeItem:删除key对应的值。
  • clear:删除所有的key,并且重置数据库。
  • length:获取仓库中key的长度。
  • keys:获取数据仓库中所有的key。
  • iterate:迭代数据库中所有的键值对,如果有一个value是undefined,就会推出,并且将 该键传入成功回调内。

配置相关API

  • setDriver:用来选择驱动或者配置数据库,应该放在第一个调用数据API之前调用。
    • 默认情况下,localForage会按照以下的顺序选择数据仓库的后后端驱动。1. IndexedDB2. WebSQL3. localStorage

  • config:见词思意,用来配置localForage的API,在调用localForage之前必须先调用,此方法设置的任何值都将保留,属性较多,案例详解。
localforage.config({// 将数据库从 “localforage” 重命名为 “Hipster PDA App”name: 'Hipster PDA App'// 配置不同的驱动优先级driver: [localforage.WEBSQL,localforage.INDEXEDDB,localforage.LOCALSTORAGE],//size:数据库的大小(以字节为单位)。现在只用于WebSQL。 默认值:4980736      size:'100000',//version:将来用来升级version:'1.0'  
});

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

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

相关文章

2024年零基础自学网络安全/Web安全,看这一篇就够了

作为一个安全从业人员,我自知web安全的概念太过于宽泛,我本人了解的也并不够精深,还需要继续学习。 但又不想新入行的人走弯路,所以今天随手写写关于web安全的内容,希望对初次遇到web安全问题的同学提供帮助&#xff…

设计模式:软件开发的秘密武器

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

HTML:注释的 5 种场景和 5 点注意事项

你好&#xff0c;我是云桃桃。 HTML 代码注释是用来在 HTML 源代码中添加一些说明性文字&#xff0c;而不会显示在页面中的内容。它们不会在浏览器中显示或渲染。 现在我们一起来看看它的语法&#xff0c;用途和注意事项吧。 注释语法 HTML 注释的基本语法格式是: <!--…

利用Nginx正向代理实现局域网电脑访问外网

引言 在网络环境中&#xff0c;有时候我们需要让局域网内的电脑访问外网&#xff0c;但是由于网络策略或其他原因&#xff0c;直接访问外网是不可行的。这时候&#xff0c;可以借助 Nginx 来搭建一个正向代理服务器&#xff0c;实现局域网内电脑通过 Nginx 转发访问外网的需求…

绝赞春招拯救计划 -- 数据结构篇

哈希表 来吧&#xff01;一文彻底搞定哈希表&#xff01; - 知乎 (zhihu.com) 百科解释&#xff1a; “散列表&#xff08;Hash table&#xff0c;也叫哈希表&#xff09;&#xff0c;是根据键&#xff08;Key&#xff09;而直接访问在内存存储位置的数据结构。也就是说&…

免费的 AI 视频生成工具 Moonvalley 厉害了!Moonvalley 怎么用(保姆级教程)

一、Moonvalley 介绍 Moonvalley&#xff0c;号称地表最强的 AI 视频生成工具&#xff0c;到底有多厉害&#xff1f;今天一起来看一下~ 这是 Moonvalley 官网的介绍&#xff1a; Moonvalley 是一个开创性的新型文本到视频的生成式 AI 模型。用简单的文本即可创建出惊人的电影和…

蓝桥杯练习系统(算法训练)ALGO-976 P0804字符串压缩

资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 编写一个函数void strcompress(char *s)&#xff0c;输入一个字符串&#xff08;只包含小写字母和空格&#xff0c;且长度小于1000&am…

MotionCtrl: A Unified and Flexible Motion Controller for Video Generation

MotionCtrl: A Unified and Flexible Motion Controller for Video Generation 这篇论文是基于VideoCrafter的&#xff0c;而VideoCrafter是基于LVDM的 关于LVDM可以看https://blog.csdn.net/Are_you_ready/article/details/136615853 2023年12月6日发表在arxiv 这篇论文讨论…

【深度学习】线性回归

Linear Regression 一个例子线性回归机器学习中的表达评价函数好坏的度量&#xff1a;损失&#xff08;Loss&#xff09;损失函数&#xff08;Loss function&#xff09;哪个数据集的均方误差 (MSE) 高 如何找出最优b和w?寻找最优b和w如何降低损失 (Reducing Loss)梯度下降法梯…

绪论——算法设计原则【数据科学与工程算法基础】

一、题记 最近情绪不太稳定&#xff0c;些许烦躁&#xff0c;也就一直没践行前边说的“学习记录”的想法。现在开始做了&#xff0c;春华易逝&#xff0c;正当时&#xff0c;有想法就去做&#xff0c;踌躇懊悔是这个年纪最不该做的事。 二、前言 之前说了分块做这个系列&#x…

101. Go单测系列1---使用monkey打桩

本文将介绍如何在单元测试中使用monkey进行打桩。 monkey支持为任意函数及方法进行打桩。 monkey介绍 monkey是一个Go单元测试中十分常用的打桩工具&#xff0c;它在运行时通过汇编语言重写可执行文件&#xff0c;将目标函数或方法的实现跳转到桩实现&#xff0c;其原理类似…

我用 Python 做了个小仙女代码蹦迪视频

前言 最近在B站上看到一个漂亮的仙女姐姐跳舞视频&#xff0c;循环看了亿遍又亿遍&#xff0c;久久不能离开&#xff01; 看着仙紫小姐姐的蹦迪视频&#xff0c;除了一键三连还能做什么&#xff1f;突发奇想&#xff0c;能不能把小仙女的蹦迪视频转成代码舞呢&#xff1f; 说…

uniapp引入jQuery

安装 npm install jquery --saveoryarn add jquery引入 import Vue from vue import jquery from "jquery"; Vue.prototype.$ jquery;<template><view>abc</view> </template><script>export default {data() {return {}}} </scr…

Vue3全家桶 - VueRouter - 【1】快速使用(创建路由模块 + 规定路由模式 + 使用路由规则 + RouterView-RouterLink)

VueRouter Vue-Router官网&#xff1b;vue-router 是 vue.js 官方给出的路由解决方案&#xff0c;能够轻松的管理 SPA 项目中组件的切换&#xff1b;安装&#xff1a;yarn add vue-router4&#xff1b; 快速使用 1.1 创建路由模块 在项目中的 src 文件夹中创建一个 router …

【智慧公寓】东胜物联嵌入式硬件解决方案,为智慧公寓解决方案商降本增效,更快实现产品规模化生产

方案背景 东胜物联本次服务的客户是一家专注于提供智慧公寓解决方案的欧洲企业&#xff0c;该公司旨在为用户提供智能&#xff0c;便捷&#xff0c;安全的生活体验。其解决方案涵盖智慧公寓控制、自动化、能源管理和智能建筑&#xff0c;它的使命是通过复杂的控制系统使用户能…

【OpenGL实现 03】纹理贴图原理和实现

目录 一、说明二、纹理贴图原理2.1 纹理融合原理2.2 UV坐标原理 三、生成纹理对象3.1 需要在VAO上绑定纹理坐标3.2 纹理传递3.3 纹理buffer生成 四、代码实现&#xff1a;五、着色器4.1 片段4.2 顶点 五、后记 一、说明 本篇叙述在画出图元的时候&#xff0c;如何贴图纹理图片…

局域网管理工具

每个组织的业务运营方法都是独一无二的&#xff0c;其网络基础设施也是如此&#xff0c;由于随着超融合基础设施等新计算技术的发展&#xff0c;局域网变得越来越复杂&#xff0c;因此局域网管理也应该如此&#xff0c;组织需要量身定制的局域网管理解决方案&#xff0c;这些解…

probiller怎么订阅

很多小伙伴想订阅probiller&#xff0c;但是不知道怎么订阅&#xff0c;这里我使用的是556150的卡订阅的&#xff0c;亲测~~ 所以有想订阅的小伙伴可以点击获取5561卡片&#xff0c;此卡0年费、0月费 下面请看订阅记录 开卡步骤请看图 卡信息在卡中心&#xff0c;cvc安全码 …

(五)关系数据库标准语言SQL

注&#xff1a;课堂讲义使用的数据库 5.1利用SQL语言建立数据库 5.1.1 create Database 5.1.2 create schema...authorization... 创建数据库和创建模式的区别&#xff1a; 数据库是架构的集合&#xff0c;架构是表的集合。但在MySQL中&#xff0c;他们使用的方式是相同的。 …

深入探索HAProxy:高性能负载均衡器的奥秘

目录 引言 一、HAProxy基础知识 &#xff08;一&#xff09;HAProxy概述 &#xff08;二&#xff09;核心特性 &#xff08;三&#xff09;支持调度算法 二、安装haproxy &#xff08;一&#xff09;下载源码包 &#xff08;二&#xff09;解决依赖环境 &#xff08;三…