sessionStorage 与 localStorage 差不多可以算作一对兄弟,它俩的暴露的 API 方法一模一样。

但两者也有不同点:

1、sessionStorage 存入的数据在页面关闭后,会自动清除。

2、相同 URL 的每个 tab 页签的 sessionStorage 会被隔离,互不影响。也就是说相同的链接,在 A 标签页打开和在 B 标签打开,A 写入的 sessionStorage 数据,B 是无法读取的!!这里与 会话 Cookie 完全不一样。

3、在页面中使用 <a target="_blank" rel="opener">window.open 打开新的标签页,sessionStorage 数据会复制,但之后的修改相互隔离。

4、sessionStorage 存入的数据会在浏览器打开期间一直保留,刷新页面或使用 ctrl + shift + t 恢复页面时,数据不会丢失。

API

sessionStorage 暴露的接口与 localStorage 一致:

// 只读属性,返回会话存储项的数目
sessionStorage.length // 获取会话存储的第 n 个键名
sessionStorage.key(n)
// 获取会话存储的值
sessionStorage.getItem(key)
// 写入会话存储
sessionStorage.setItem(key, value)
// 删除会话存储
sessionStorage.removeItem(key)
// 清空所有会话存储
sessionStorage.clear()

API 使用示例:

(() => {
// 写入数据
sessionStorage.setItem('type', '公众号');
sessionStorage.setItem('name', '前端路引'); // 获取会话存储长度
console.log(sessionStorage.length); // 循环打印会话存储
for (let i = 0; i < sessionStorage.length; i++) {
const key = sessionStorage.key(i);
const value = sessionStorage.getItem(key);
console.log(`${key}: ${value}`);
}
// 移除单个会话存储
sessionStorage.removeItem('name');
// 移除所有会话存储
sessionStorage.clear();
})()

无法监听存储数据变化

不像 localStorage,sessionStorage 没有暴露 onchange 事件,所以无法监听到数据变化,就算模拟自定义事件,也只能在当前页面中获得事件,无法跨页面通信。以下代码只能在本页面中监听 sessionStorage 数据改变:

(() => {
// 移除所有会话存储
sessionStorage.clear(); // 监听 storage 事件
window.addEventListener('storage', e => {
console.log(e);
}) // 自定义写入函数,封装事件派发
function setItem (key, value) {
// 模拟 storage 事件
const ev = new StorageEvent('storage', {
key,
newValue: value,
oldValue: sessionStorage.getItem(key),
url: location.href,
});
window.dispatchEvent(ev);
sessionStorage.setItem(key, value);
} setItem('type', '公众号');
setItem('name', '前端路引');
})()

测试结果:

新开页面复制 sessionStorage

a 标签中添加 rel="opener" 可令新开的页面获得父页面中的 sessionStorage 数据(复制方式)。

window.open 方法打开的页面也是一样的道理。

注意:此时获得数据仅仅是副本,不共享,所以在新页面或旧页面中修改数据时,两者互不影响。

a 标签默认是 noopener,如果不显示设置 rel="opener",无法获得数据副本!!

测试代码:

<a
href="./example-84-3.html"
target="_blank"
>a 标签打开本页面</a><br><br>
<a
href="./example-84-3.html"
target="_blank"
rel="opener"
>a 标签 opener 打开本页面</a><br><br>
<a
href="./example-84-3.html"
target="_blank"
rel="noopener"
>a 标签 noopener 打开本页面</a><br><br> <button
onclick="window.open('./example-84-3.html')"
>window.open 打开本页面</button><br><br>
<button
onclick="window.open('./example-84-3.html', '_blank', 'noopener')"
>window.open noopener 打开本页面</button><br><br> <button id="set">写入新的 sessionStorage</button><br><br>
<button id="get">获取 sessionStorage</button><br><br> <div id="output"></div> <script>
(() => {
const output = document.querySelector('#output');
document.querySelector('#set').addEventListener('click', e => {
sessionStorage.setItem('now', Date.now());
}) document.querySelector('#get').addEventListener('click', e => {
const now = sessionStorage.getItem('now');
output.innerText = now ?? '无';
})
})()
</script>

测试结果:

大小限制

localStorage 一样限制 5MB 大小(所有键值加在一起的长度),溢出后写入报错,此处推荐阅读前一篇文章:{%post_link 'wechat-web-front-end-83'%}

测试代码:

(() => {
// 移除所有会话存储
sessionStorage.clear();
const key = 'name';
const max = 5 * 1024 * 1024;
// 测试极限值
// const value = 'a'.repeat(max - key.length);
// 测试中文
// const value = '中'.repeat(max - key.length);
// 测试溢出
const value = 'a'.repeat(max - key.length + 1);
sessionStorage.setItem(key, value);
// 测试多个项溢出情况
// sessionStorage.setItem('key', '1');
// 测试与 localStorage 是否共用存储空间
// localStorage.setItem('key', '1');
})()

溢出结果:

结论:setItem 多个子项时,公用 5MB 存储空间(中英文计算方式一致),溢出时写入报错,并且与 localStorage 不共用存储空间!使用 rel="opener" 打开链接时,会获得父页面的副本数据,所以新开的页面仅能写入 5MB - 副本数据 等到的剩下空间。

可使用以下代码判断是否拥有副本数据:

if (window.opener) {
// opener 存在表示拥有副本
// 极限情况再写入新的数据报错
sessionStorage.setItem('now', Date.now());
}

刷新与恢复页面

页面刷新时和关闭页面后再使用 ctrl+shift+t 恢复页面,sessionStorage 数据不会丢失。

测试代码:

<button id="set">写入新的 sessionStorage</button><br><br>
<button id="get">获取 sessionStorage</button><br><br> <div id="output"></div> <script>
(() => {
const output = document.querySelector('#output');
document.querySelector('#set').addEventListener('click', e => {
sessionStorage.setItem('now', Date.now());
}) document.querySelector('#get').addEventListener('click', e => {
const now = sessionStorage.getItem('now');
output.innerText = now ?? '无';
})
})()
</script>

效果:

写在最后

sessionStorage 仅支持字符串存储,所以 JS 中用的 JSON 数据需要格式化为字符串存储~~

sessionStorage 一般多用于临时数据存储,比如一些表单填写的临时数据,单页应用页面间的数据传递等。

其生命周期有点短暂,浏览器或标签页关闭就会消失,就像浮游一样,朝生暮死...

Web前端入门第 84 问:JavaScript sessionStorage 那些容易踩坑的地方的更多相关文章

  1. web前端入坑第五篇:秒懂Vuejs、Angular、React原理和前端发展历史

    秒懂Vuejs.Angular.React原理和前端发展历史 2017-04-07 小北哥哥 前端你别闹 今天来说说 "前端发展历史和框架" 「前端程序发展的历史」 「 不学自知, ...

  2. web前端入坑第二篇:web前端到底怎么学?干货资料! 【转】

    http://blog.csdn.net/xllily_11/article/details/52145172 版权声明:本文为博主[小北]原创文章,如要转载请评论回复.个人前端公众号:前端你别闹,J ...

  3. web前端(13)—— 了解JavaScript,JavaScript的引入方式

    从本篇博文开始,将进入web前端方便最关键最重要的部分——javascript,学到后面你就知道它真的太重要了 什么是JavaScript JavaScript一种直译式的脚本语言,是一种动态类型.弱 ...

  4. WEB前端工程师整理的原生JavaScript经典百例

    一.原生JavaScript实现字符串长度截取 二.原生JavaScript获取域名主机 三.原生JavaScript转义html标签 四.原生JavaScript时间日期格式替换 Date.prot ...

  5. Web前端基础怎么学? JavaScript、html、css知识架构图

    以前开发者只要掌握 HTML.CSS.JavaScript 三驾马车就能胜任一份前端的工作了.而现在除了普通的编码以外,还要考虑如何性能优化,如何跨端.跨平台实现功能,尤其是 AI.5G 技术的来临, ...

  6. web前端学习之HTML CSS/javascript之一

    前端编码之路之坎坷,web前端应该一直是个战场吧,各种浏览器的不兼容,各种小细节的修改,要往一个好的产品经理方向走,实在是难,昨天听了一位十年经验的产品经理讲座,最重要的恐怕就是协调资源的能力,而协调 ...

  7. Android零基础入门第84节:引入Fragment原来是这么回事

    随着大众生活水平的提高,再加上移动互联网的迅速发展,几乎每个人都至少拥有一台搭载Android系统的移动设备.Android设备的多样性给我们带来了很大的便捷,各Android设备拥有不同分辨率和不同 ...

  8. Web前端开发规范【HTML/JavaScript/CSS】

    前言 这是一份旨在增强团队的开发协作,提高代码质量和打造开发基石的编码风格规范,其中包含了 HTML, JavaScript 和 CSS/SCSS 这几个部分.我们知道,当一个团队开始指定并实行编码规 ...

  9. web前端——实例中学习css,javascript

    最近闲暇时候在研究前端的样式和js,以前都是从w3school上看看那些选择器和DOM操作方法很少去实际做demo来研究,做的过程当中才真切感觉到纸上得来终觉浅,看得懂跟能做出东西完全两码事,尤其在定 ...

  10. 文成小盆友python-num14 - web 前端基础 html ,css, JavaScript

    本部分主要内容 html - 基础 css - 基础 一.html 标签 html 文档标签树如下: head 部分 Meta(metadata information) 提供有关页面的元信息,例:页 ...

随机推荐

  1. MAC系统13.2,安装最新版logi options+,打开一直转圈

    我联系官网客服,按照他给的步骤成功的安装了options+,你试试 请抽出时间按照下面列出的故障排除步骤尝试解决问题. 卸载我们所有的软件 删除剩余文件 步骤 1:打开 Finder,在菜单栏中选择& ...

  2. FPGA使用两个HC595驱动8位数码管

    FPGA使用两个HC595驱动8位数码管 本文章给出使用FPGA3根线来驱动8位数码管的示例代码,输入为disp_data,共7*8=56位,输出输入如图所示. 硬件方面参数 该程序只能控制数码管的7 ...

  3. python基础—集合

    一.集合(数字,字符串,元组) 1.定义 由不同元素组成的集合,集合中是一组无序排列的哈希值,可以作为字典的key 2.特性 无序,不同元素组成,必须是不可变类型 3.set输出与去重 s=set(' ...

  4. Springboot笔记<10>常用注解总结

    Springboot常用注解总结 • 项目配置注解 1.@SpringBootApplication 注解 @SpringBootApplication是一个复合注解,包含了@SpringBootCo ...

  5. kubernetes配置glusterfs动态存储

    GlusterFS分布式文件系统 一.简单介绍 分布式存储按其存储接口分为三种:文件存储.块存储.对象存储 文件存储 通常支持POSIX接口(如glusterFS,但GFS.HDFS是非POSIX接口 ...

  6. ArcGIS工具操作报错999999的通用处理方式

      本文介绍一种解决ArcGIS中ERROR 999999报错(Configuration RasterCommander ImageServer can not be started)的方法.    ...

  7. 函数使用十三:BAPI_REQUISITION_CREATE

    *&---------------------------------------------------------------------**& Report  ZBAPI_REQ ...

  8. Java变量类型识别

    方法: 1.反射方式,成员变量的类型判断2.isInstance用法3.利用泛型识别类型一.新建测试类 import java.util.Date; import com.cxyapi.generic ...

  9. 上线啦丨FlinkX1.12 Beta版正式在Github开源

    万众期待的FlinkX1.12的Beta版今天正式在Github社区开源上线啦!这是FlinkX技术团队潜心打造的新版本的FlinkX,设计文档和使用文档已在社区中推送,大家可以随时下载查阅,喜欢的同 ...

  10. Java学习篇(四)—— Java 多线程

    如何创建一个线程? Java创建线程有两种方法,这里对三种方法做一个梳理,方便理解. 实现Runnable接口和run()方法 Java的接口就是一种协议,约定了想要被统一管理的类要遵循的协议.在Ja ...