写该系列文章的初衷是“让每位前端工程师掌握高频知识点,为工作助力”。这是前端百题斩的第24斩,希望朋友们关注公众号“执鸢者”,用知识武装自己的头脑。

打开浏览器的开发者工具中的Application部分,可以看到浏览器支持五种存储方式:localStorage、sessionStorage、IndexedDB、WebSQL、Cookie。其中W3C 官方在 2011 年 11 月声明已经不再维护 Web SQL Database 规范,所以本次主要讨论另外的三类四种存储方式:Cookie、Storage、IndexedDB。

image.png

24.1 Cookie

24.1.1 定义

Cookie是一个保存在浏览器中的简单的文本文件,该文件与特定的Web文档关联在一起,保存了该浏览器访问这个Web文档时的信息,当浏览器再次访问这个Web文档时这些信息可供该文档使用。(HTTP是无状态的协议,即HTTP协议本身不对请求和响应之间的通信状态进行保存,为了实现期望的保存状态功能,引入了cookie技术)

24.1.2 Cookie组成

在了解Cookie组成之前先了解一下Cookie的整个请求流程,这个流程分为两类:一类是没有Cookie信息状态下的请求,另一类是存有Cookie状态下的请求。

通过上面的流程图可以看出,Cookie是在服务端生成的,经过查询资料了解到其是在从服务端发送的响应报文内的一个叫做Set-Cookie的首部字段信息,响应报文中有该首部字段则通知客户端保存Cookie,则Cookie的组成则跟Set-Cookie可以设置哪些值相关,目前主要有以下几类:

  1. NAME=VALUE Cookie的名称和值,其中NAME是唯一标识cookie的名称,不区分大小写;VALUE是存储在Cookie里的字符串值,该值必须经过URL编码。

  2. Domain=域名 Cookie有效的域,发送到这个域的所有请求都会包含对应的Cookie。(若不指定则默认为创建Cookie的服务器的域名)

  3. Path=PATH 请求URL中包含这个路径才会把Cookie发送到服务器(若不指定则默认为文档所在的文件目录)

  4. Expires=DATE Cookie的有效期,默认情况下,浏览器会话结束后会删除所有cookie。

  5. Secure 设置后仅在HTTPS安全通信时才会发送Cookie

  6. HttpOnly 设置后只能在服务器上读取,不能再通过JavaScript读取Cookie

const express = require('express');const app = express();app.get('/', (req, res) => {res.cookie('myCookie', 'myCookie', {expires: new Date(Date.now() + 900000),secure: true,httpOnly: true});res.send('get请求已经被处理');
})
app.listen(8090, () => {console.log('8090端口已经启动!!!');
});

通过请求 http://127/.0.0.1:8090 来看看其结果:

  1. 第一次返回的Cookie结果

  2. 后续请求所带的Cookie信息

24.1.3 Cookie特点

  1. 每个Cookie不超过4096字节;

  2. 每个域中Cookie个数有限制,就拿最新版来说:IE和Edge不超过50个;Firefox不超过150个;Opera不超过180个;Safari和Chrome没有限制;

  3. Cookie超过单个域的上限,浏览器会删除之前设置的Cookie;

  4. 创建的Cookie超过最大限制,该Cookie会被静默删除;

  5. 可设置失效时间,没有设置则会话结束会删除Cookie;

  6. 每个请求均会携带Cookie,若Cookie过多会带来性能问题;

  7. 受同源策略限制

24.1.4 Cookie的操作

Cookie存储到浏览器端之后仍然可以对其进行读、写、删除,由于js对Cookie操作的支持并不是很友好,所以需要进行一些简单的封装。

class CookieUtil {// 获取Cookie中的对应属性static get(name) {const cookies = document.cookie;const cookiesArr = cookies.split(';');for (let index = 0; index < cookiesArr.length; index++) {const presentCookieArr = cookiesArr[index].split('=');if (presentCookieArr[0] === name) {return presentCookieArr[1];}}return null;}// 设置对应的Cookie值static set(name, value, expires, path, domain, secure) {let cookieText = `${name}=${value}`;if (expires instanceof Date) {cookieText += `; expire=${expires.toGMTString()}`;}if (path) {cookieText += `; path=${path}`;}if (domain) {cookieText += `; domain=${domain}`;}if (secure) {cookieText += `; secure`;}document.cookie = cookieText;}// 删除对应的Cookiestatic deleteCookie(name) {CookieUtil.set(name, '', new Date(0));}
}

24.2 Web Storage

Web Storage的目的是解决通过客户端存储不需要频繁发送回服务器的数据时使用cookie的问题,其提供了cookie之外的存储会话数据的途径和跨会话持久化存储大量数据的机制,其主要有两个对象:localStorage和sessionStorage,localStorage是永久存储机制,sessionStorage是跨会话的存储机制。

24.2.1 sessionStorage

sessionStorage是跨会话的存储机制,具有以下特点:

  1. sessionStorage对象值存储会话数据,其生命周期会存储到浏览器关闭。(在该过程中刷新页面其数据不受影响)

  2. 浏览器在实现存储写入时使用同步阻塞方式,数据会被立即提交到存储。

  3. 独立打开同一个窗口同一个页面或一个Tab,sessionStorage也是不一样的。

  4. 存储空间大小限制为每个源不超过5M。

// 使用方法存储数据
sessionStorage.setItem('sessionName1', 'value1');
// 使用属性存储数据
sessionStorage.sessionName2 = 'value2';// 使用方法取得数据
const sessionValue1 = sessionStorage.getItem('sessionName1');
console.log('sessionValue1的值为:', sessionValue1);
// 使用属性取得数据
const sessionValue2 = sessionStorage.sessionName2;
console.log('sessionValue2的值为:', sessionValue2);// 循环遍历sessionStarage
for (let index = 0; index < sessionStorage.length; index++) {// 使用key()方法获得指定索引处的名称const key = sessionStorage.key(index);const value = sessionStorage.getItem(key);console.log('循环遍历结果:', key, value);
}// 使用方法删除值
sessionStorage.removeItem('sessionName1');
// 使用delete删除值
delete sessionStorage.sessionName2;// 使用clear()方法清空sessionStorage
sessionStorage.clear();

24.2.2 localStorage

localStorage是永久存储机制,具有以下特点:

  1. 生命周期是永久的,除非被清除,否则永久保存。

  2. 存储空间大小限制为每个源不超过5M。

  3. 受同源策略限制。

  4. 浏览器存储时采用同步存储方式。

// 使用方法存储数据
localStorage.setItem('localName1', 'value1');
// 使用属性存储数据
localStorage.localName2 = 'value2';// 使用方法取得数据
const localValue1 = localStorage.getItem('localName1');
console.log('localValue1的值为:', localValue1);
// 使用属性取得数据
const localValue2 = localStorage.localName2;
console.log('localValue2的值为:', localValue2);// 循环遍历localStarage
for (let index = 0; index < localStorage.length; index++) {// 使用key()方法获得指定索引处的名称const key = localStorage.key(index);const value = localStorage.getItem(key);console.log('循环遍历结果:', key, value);
}// 使用方法删除值
localStorage.removeItem('localName1');
// 使用delete删除值
delete localStorage.localName2;// 使用clear()方法清空localStorage
localStorage.clear();

24.3 IndexedDB

24.3.1 IndexedDB整个结构

对于整个IndexedDB为上述图中所示:

  1. 一个域名下可以包含多个数据库;

  2. 一个数据库中包含多个对象仓库,就类似与Mysql一个库中有多张表一样。

  3. 每个对象仓库中包含多条数据记录。

24.3.2 主要特点

IndexedDB是浏览器中存储结构化数据的一个方案,其设计几乎是完全异步的,主要有以下特点:

  1. 键值对存储 在对象仓库中,数据以“键值对”形式保存,每个数据记录都有独一无二的主键。

  2. 异步 IndexedDB操作时不会锁死浏览器,用户依然可以进行其它操作。

  3. 支持事务 一些列操作步骤之中只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。

  4. 受同源策略限制 只能访问自身域名下的数据库,不能跨域访问数据库。

  5. 存储空间大 每个源都有存储空间的限制,而且这个限制跟浏览器有关,例如Firefox限制每个源50MB,Chrome为5MB。

  6. 支持二进制存储 不仅可以存储字符串,还可以存储二进制数据(ArrayBuffer和Blob)

24.3.3 数据库操作

IndexedDB像很多其它数据库一样有很多操作,下面就通过实战的方式一起了解这些操作。

24.3.3.1 初始化数据库

第一步是初始化数据库,传入创建的数据库名和版本,获取对应的数据库操作实例。

class IndexedDBOperation {constructor(databaseName, version) {this.atabaseName = databaseName;this.version = version;this.request = null;this.db = null;}// 数据库初始化操作init() {this.request = window.indexedDB.open(this.databaseName, this.version);return new Promise((resolve, reject) => {this.request.onsuccess = event => {this.db = event.target.result;console.log('数据库打开成功');resolve('success');};this.request.onerror = event => {console.log('数据库打开报错');reject('error');};this.request.onupgradeneeded = event =>{this.db = event.target.result;console.log('数据库升级');resolve('upgradeneeded');};});}
}
24.3.3.2 对象仓库操作

数据是在对象仓库中存储的,创建好数据库后则需要创建所需的数据仓库

class IndexedDBOperation {// ……// 创建数据仓库createObjectStore(objectStoreName, options) {let objectStore = null;if (!this.db.objectStoreNames.contains(objectStoreName)) {objectStore = this.db.createObjectStore(objectStoreName, options);}return objectStore;}
}
24.3.3.3 数据操作

不管是关系型数据库还是非关系型数据库,CURD肯定是必不可少的,谁让我们是“CURD工程师”呢!!!

class IndexedDBOperation {// ……// 新增内容add(objectStore, content) {objectStore.add(content);}// 获取内容get(objectStore, id) {const request = objectStore.get(id);return new Promise((resolve, reject) => {request.onsuccess = resolve;request.onerror = reject;});}// 更新内容update(objectStore, content) {const request = objectStore.put(content);request.onsuccess = event => {console.log('更新成功');};request.onerror = event => {console.log('更新失败');};}// 删除内容remove(objectStore, deleteId) {const request = objectStore.delete(deleteId);request.onsuccess = event => {console.log('删除成功');};request.onerror = event => {console.log('删除失败');};}
}
24.3.3.4 遍历内容

提到IndexedDB数据库,不得不提其的游标操作。

class IndexedDBOperation {// ……// 打印全部数据printAllDataByCursor(objectStore) {const cursorRequest = objectStore.openCursor();cursorRequest.onsuccess = event => {const cursor = event.target.result;if (cursor) {console.log(`利用游标打印的内容,id为${cursor.key}, 值为${cursor.value}`);// 移动到下一条记录cursor.continue();}};}
}
24.3.3.5 调用代码

上面写了一个数据库的类,但是仍然不知道怎么调用呀,下面就用一个demo讲述其调用。

const indexedDBOperation = new IndexedDBOperation('dbName1', 1);
indexedDBOperation
.init()
.then(type => {const objectStoreName = 'testObjectStore';if (type === 'upgradeneeded') {indexedDBOperation.createObjectStore(objectStoreName, {keyPath: 'id'});}const transaction = indexedDBOperation.db.transaction([objectStoreName], 'readwrite');const objectStore = transaction.objectStore(objectStoreName);indexedDBOperation.get(objectStore, 1).then(event => {if (event.target.result) {indexedDBOperation.update(objectStore, {id: 1,name: '执鸢者+纸鸢'});console.log('数据库中已经存在', event.target.result, ',则进行更新操作');}else {indexedDBOperation.add(objectStore, {id: 1,name: '执鸢者'});console.log('数据库中不存在,则进行添加');}}).catch(console.log);indexedDBOperation.printAllDataByCursor(objectStore);transaction.onsuccess = event => {console.log('事务操作成功');};transaction.onerror = event => {console.log('事务操作失败');};transaction.oncomplete = event => {console.log('整个事务成功完成');}
})
.catch(console.log);

1.如果觉得这篇文章还不错,来个分享、点赞、在看三连吧,让更多的人也看到~

2.关注公众号执鸢者,领取学习资料,定期为你推送原创深度好文

3.关注公众号进群,里面大佬多多,一起向他们学习

1. 前端百题斩[001]——typeof和instanceof

2. 前端百题斩【002】——js中6种变量声明方式

3. 前端百题斩【003-004】——从基本类型、引用类型到包装对象

4. 前端百题斩【005】—— js中9种遍历对象的方法

5. 前端百题斩【006】——js中三类字符串转数字的方式

6. 前端百题斩【007】——js中必须知道的四种数据类型判断方法

7. 前端百题斩【008-009】——从JavaScript的代码执行过程到函数执行过程

8. 前端百题斩【010】——通俗易懂的JavaScript执行上下文

9. 前端百题斩【011】——通俗易懂的变量对象

10. 前端百题斩【012】——js中作用域及作用域链的真面目

11. 前端百题斩【013】——用“闭包”问题征服面试官

12. 前端百题斩【014】——js中的这些“this”指向都值得了解

13. 前端百题斩【015】——快速手撕call、apply、bind

14. 前端百题斩【016】——原型、构造函数和实例之间的奇妙关系

15. 前端百题斩【017】——一基础、二主线、双机制理解原型链

16. 前端百题斩【018】——从验证点到手撕new操作符

17. 前端百题斩【019】——数组中方法原理早知道

18. 前端百题斩【020】——竟然有五种方式实现flat方法

19. 前端百题斩【021】——通俗易懂的防抖与节流

20. 前端百题斩【022】——开拓思路之三种方式实现字符串转驼峰

21. 前端百题斩【023】——赋值、浅拷贝、深拷贝大PK

22. 前端也要懂机器学习(上)

23. 前端也要懂机器学习(下)

24. 学架构助力前端起飞

25. 假如只剩下canvas标签

26. Vue源码思想在工作中的应用

27. 一文搞定Diff算法

28. 百度、小红书三面,均遇“赛马”问题

29. 十五张图带你彻底搞懂从URL到页面展示发生的故事

30. 一文搞懂Cookie、Storage、IndexedDB

前端百题斩【024】——我从浏览器控制台看到了五种存储方式相关推荐

  1. 前端百题斩【028】——浏览器中的请求们

    写该系列文章的初衷是"让每位前端工程师掌握高频知识点,为工作助力".这是前端百题斩的第28斩,希望朋友们关注公众号"执鸢者",用知识武装自己的头脑. 通过浏览器 ...

  2. 前端百题斩【006】——js中三类字符串转数字的方式

    写该系列文章的初衷是"让每位前端工程师掌握高频知识点,为工作助力".这是前端百题斩的第6斩,希望朋友们关注公众号"执鸢者",用知识武装自己的头脑. js中字符串 ...

  3. 前端百题斩【029】——原来浏览器中存在五类进程

    写该系列文章的初衷是"让每位前端工程师掌握高频知识点,为工作助力".这是前端百题斩的第29斩,希望朋友们关注公众号"执鸢者",用知识武装自己的头脑. 浏览器已经 ...

  4. 前端百题斩【030】——神奇的浏览器渲染流程

    写该系列文章的初衷是"让每位前端工程师掌握高频知识点,为工作助力".这是前端百题斩的第30斩,希望朋友们关注公众号"执鸢者",用知识武装自己的头脑. 本篇文章是 ...

  5. 前端百题斩【032】——两个角度一个实战了解事件循环

    写该系列文章的初衷是"让每位前端工程师掌握高频知识点,为工作助力".这是前端百题斩的第32斩,希望朋友们关注公众号"执鸢者",用知识武装自己的头脑. 111 9 ...

  6. 前端百题斩【035】——一文了解HTTP缓存

    写该系列文章的初衷是"让每位前端工程师掌握高频知识点,为工作助力".这是前端百题斩的第35斩,希望朋友们关注公众号"执鸢者",用知识武装自己的头脑.提前透露一下 ...

  7. 前端百题斩【027】——解决跨域的常用利器CORS全解

    写该系列文章的初衷是"让每位前端工程师掌握高频知识点,为工作助力".这是前端百题斩的第27斩,希望朋友们关注公众号"执鸢者",用知识武装自己的头脑. 27.1 ...

  8. 前端百题斩【025】——原来跨域也是可以进行分类的

    写该系列文章的初衷是"让每位前端工程师掌握高频知识点,为工作助力".这是前端百题斩的第25斩,希望朋友们关注公众号"执鸢者",用知识武装自己的头脑. 25.1 ...

  9. 前端百题斩【031】——从渲染流程认识重绘和回流

    写该系列文章的初衷是"让每位前端工程师掌握高频知识点,为工作助力".这是前端百题斩的第31斩,希望朋友们关注公众号"执鸢者",用知识武装自己的头脑. 在&quo ...

最新文章

  1. 4.5-4.9 磁盘格式化,磁盘挂载,手动增加swap空间
  2. JQuery选择器中的可见性筛选
  3. android 悬浮球简书,轻松自制flyme悬浮球
  4. 以链表为载体学习C++(4)
  5. OpenShift 4 - 使用Operator安装Gitea
  6. 使用MSTest v2进行单元测试的并行化
  7. ubuntu上 grafana + influxdb + telegraf 安装配置
  8. 【bug解决方案】powershell 中无法激活 conda 环境 /Anaconda 使用 powershell 无效
  9. 高中信息技术:信息技术初步、计算机基础、office办公软件
  10. svnadmin命令[转]
  11. 废旧手机变身服务器,打造私人云盘
  12. 仅用钩子实现QQ桌球瞄准器
  13. 苹果手机怎么关闭爱奇艺自动续费_爱奇艺回应涨价为用户创造优质服务,小编建议用户先关闭自动续费...
  14. php stripslashes和addslashes的区别
  15. Ground Rover with Mavros
  16. 『 再看.NET7』看看required属性有什么不同
  17. Rate Limiting Algorithms (限流算法)
  18. mysql 8.0.13解压版安装_mysql 8.0.13 解压版安装配置方法图文教程
  19. SpringBoot之从零搭建博客网站
  20. 【第11天】SQL进阶-索引的创建、删除(SQL 小虚竹)

热门文章

  1. 南斯拉夫 苏联 捷克斯洛伐克
  2. python百度贴吧 发帖时间_python爬取贴吧帖子
  3. 用计算机弹小酒窝数字,林俊杰最美十句歌词 第一句来自小酒窝,第二句很是经典...
  4. ConstraintLayout的取消使用 修改默认使用linearLayout不是这个
  5. 笔记本计算机声卡开关,电脑开关机都没有声音是怎么回事,是不是声卡坏了
  6. 亚马逊 amazon connect(呼叫中心)
  7. centos 6.8下载地址
  8. Carson带你学JVM:图文解析Java虚拟机内存结构
  9. “温酒吧”不得不说的故事
  10. 5G与4G ,DSRC 频段