漫谈 Web Storage API 既本地存储的 8 个 Features 和 20 个 BUG

漫谈 Web Storage API 既本地存储的 8 个 Features 和 20 个 BUG

Storage 是种简单又复杂的本地数据存储方法,简单在于它使用方便,复杂在于它有无数的 BUG,为了能够安心的使用它,XJ 花了很多时间,写了一个开源的 xj.storage 插件,但在这篇文章中,插件并不是重点,XJ 在编写插件的过程中,通过查阅资料和实践,积累了大量关于 Storage 的笔记,本着记录和开源的想法,于是将那些笔记整理成了这篇文章,希望能帮到其他需要用到 Storage 的开发者。

Storage 有两个实例对象既 localStoragesessionStorage,这两个实例对象的属性和方法都是相同的,只是使用的场景和一些细节表现有所区别,XJ 就不在这里科普这两个实例对象的基础内容了,这些知识大伙随意搜索都能找到一堆相关的文章,在这里我们着重讨论 Storage 存在的一些难以弄清的特性细节,以及一些 BUG 和解决方案,即使你十分熟悉 Storage,也应该会有些意外发现的。


01. Storage 的 8 个 Features

Storage 存储的一些表现细节,经常会让人感觉到模模糊糊,诸如最大 5MB 的配额,究竟是 localStoragesessionStorage 平分的?还是共用的?还是说各自有享有?配额在面对子域名不同的跨域时是如何生效的?这类问题你往往很难有一个全面的认识,这是因为标准在不同浏览器的最终表现会存在差异,所以科普向文章就算有提到也不一定完全准确,接下来我们就来讲讲这些模模糊糊的细节。

————

01.01. 同个窗口下的 sessionStorage 数据才会被共享

localStorage 按照标准只要 protocol(协议) 和 hostname(主机名) 和 port(端口)都相同(同源),就能读写同一份 localStorage 数据,而 sessionStorage 的要求比 localStorage 严苛,除了协议主机名端口要求相同不能跨域之外,它还要求在同个窗口(或者说同个 Tab 标签页)才行,如果是两个窗口(或者说两个 Tab 标签页),那么即使 URL 相同,也是读取不到数据的,并且在操作数据时,Storage 事件也不会响应,唯一的一种例外,就是在页面中的 iframe,如果 iframesrc 地址和页面是同源的,那么页面和 iframe 所在的页面,数据就可以被共享,并且在操作数据的时候,Storage 事件也会在页面和 iframe 所在的页面之间被响应。

————

01.02. Storage 的标准存储配额究竟是如何进行划分的

同源的 localStoragesessionStorage 根据标准各自享有 5MB 的配额,加起来就是 10MB,但并非所有浏览器的配额都是 5MB,在早期标准尚未明确的时候,有些浏览器是使用了 2.5MB 或 10MB 的配额,而在之后即使是标准已经明确了,还是有部分浏览器的配额并不是 5MB,例如说 Android4.3 和 Android7.0,这两个版本的 Android Browser 配额就只有 2.5MB,这实际上是一个 BUG,你可以到这个 https://stackoverflow.com/questions/2989284 页面了解更多的配额细节,如果想了解你的浏览器究竟能存多少内容,可以到这个 https://arty.name/localstorage.html 页面或者这个 http://dev-test.nemikor.com/web-storage/support-test/ 页面在线测试。

————

01.03. Storage 键值对存储的一些字符串数值计算细节

首先是存储空间不区分单双字节,也就是说单字节的数字字母和双字节的中文符号,都是被算做 1,但 Unicode 编码大于 65535 的四字节字符会被算作是 2,其次是键值对的 key 和 value 都会占据空间,并非只有 value 才会被计算,最后是 setItem(key, null) 这种写法,null 会被转遍为字符串,所以它会占用 4 个字符,而不是 0 个字符,所以实际上最后可用的存储空间会比你想象中更少。

————

01.04. 关于 sessionStorage 5MB 存储配额的其他细节

在上面的第一节中,我们有提到 sessionStorage 的数据在不同窗口(或者说不同 Tab 标签页)之间不能共享,在上面第二节中,我们有提到 sessionStorage 根据标准享有 5MB 的配额,所以实际上 sessionStorage 是在每个页面(或者说每个 Tab 标签页)享有 5MB 的配额,但如果页面中有同源的 iframe 标签页面,则 5MB 的配额会和这些 iframe 标签页面共享,但是单独打开这些 iframe 标签的 src 属性所指向的地址,这些页面不会出现之前设置的数据,因为不是同个窗口或 Tab 标签页,它们又单独享有 5MB 配额。

————

01.05. key() 方法无法确保键值对被获取时的先后顺序

localStorage.key() 方法和 sessionStorage.key() 方法,都是传入索引数值就可以得到对应位置上的数据(当然前提是索引的目标上确实有数据),但索引的数值大小和你存入数据的先后顺序并没有什么必然的关系,例如说按顺序存入了 a, b, c 三个数据,但是使用 key(1), key(2), key(3) 获取数据时,不一定能依次得到 a, b, c 三个数据,这是因为存入 Storage 对象内的数据,它们排列顺序由浏览器厂商自己决定,不一定是按照存入的顺序进行排序的,当增加或者删除数据时,索引对应的值也可能有变化,Chrome 浏览器可能会自行把 key 值排序后再去输出,而 IE 和 Firefox 则不会按照顺序,它们既不会自动排序,也不会按照写入时的顺序。

————

01.06. 尽量使用标准方法来进行操作并注意数据的键名

假设执行了 localStorage.setItem('constructor', 'test') 这样的操作,会发生什么事?我们能成功的存入这个数据吗?答案是可以的,但存入后只能用 localStorage.getItem('constructor') 这样的写法来获取 'test' 的结果,那么在存入数据后对象本身的 constructor 属性会受到影响吗?答案是并不会,localStorage.constructor 依然会返回 Storage 构造函数,在大多数基础教程中都提到,除了用 setItem()getItem() 之外,也可用中括号如 localStorage[key] 或点运算符如 localStorage.key 来对数据进行存取操作,但同时那些教程也会提醒你最好不要这样做,因为这是不规范的,而更深层次的原因,首先是后面第二章的 BUG 中我们将会提到的,中括号的写法和点运算符的写法在 IE 中可能会引发 BUG,其次是如果使用中括号的写法或点运算符的写法来存取数据,假如数据的名称和 localStorage 对象或 sessionStorage 对象原有的属性或者方法重复了,就可能导致一些可怕的后果,例如说会把对象继承来的属性或方法覆盖,或者是获取的时候返回错误的结果值,所以尽量使用标准方法来操作并注意数据的键名不要重复。

————

01.07. 5MB 的存储配额也是有可能会把我们的硬盘挤爆

相关文章:https://feross.org/fill-disk/... 这个网站试试看,浏览器之所以没有根据标准限制总的存储配额,是因为诸如 GitHub 或 wordPress 等网站,它们允许用户使用二级域名创建自己的站点,在这种情况下 Storage 空间被限制,就有可能导致主站点和子站点的存储量不够用,但是说到底,这个问题对于网站开发者和用户而言都是无解的,因为标准如何实行是浏览器厂商的问题,网站开发者根本无法控制,只能自觉的不要滥用,而站点的存储空间是否会被滥用则取决于网站开发者的自觉,用户也没法控制,所以这个现象,我们了解一下也就罢了,毕竟空间总量,限制有限制的缺点,不限制有不限制的好处,这个问题其实并没有特别完美的解决方案。

————

01.08. 借助 JSON 数据格式来保存数据时存在的局限性

基本上跟 Storage 存储相关的插件,无一例外都是用 JSON.stringify() 方法转存数据,之后获取数据时再用 JSON.parse() 方法对数据进行解析,以此来让 Storage 能够支持其他类型的数据,而不是局限于字符串,但使用 JSON 作为数据的中转格式也是有局限的,JSON 作为一种通用的数据存储格式,它还需要考虑到其它语言是否可解析,所以它不会去支持一些在其他语言上无法被识别的类型值,这也是为什么我们无法在 JSON 中存储 undefinedSymbol 等类型值,也无法保存 NaNInfinity 等特殊值的原因。


02. Storage 的 20 个 BUG

下面提到的 BUG,前面九个是 canIuse 上有记录的,后面那些 BUG 则是 XJ 在查找资料以及实践的时候发现的,虽然有些 BUG 只存在于一些罕见的场景或老旧的浏览器,在当前的环境下可能已经没什么意义了,即使不知道且不解决也无所谓,但 XJ 还是决定尽可能的将它们罗列出来,也许还会有人需要用到呢?但个人的见识总是有限的,也欢迎各位同行积极反馈,争取就算解决不了,也起码有个记录。

————

02.01. 在 IE11 中可能会无法同步 localStorage 的值

问题描述:https://stackoverflow.com/que...,IE11 在不同的 Tab 标签页面之间无法正确同步 localStorage 的值。

解决方案:这个问题实际上是 IE 的 localStorage 对象无法及时自动更新导致的,在 A 页面修改数据,在 B 页面无法读取到这个被修改过的数据,B 页面会继续得到修改前的旧值,解决这个问题的方法有两种,第一种是在 B 页面获取数据时先用 setItem() 存入一个随机数,以此强制 localStorage 对象更新,更新后再获取数据就不会出错了,第二种则是绑定 Storage 事件,在这个事件中监听目标数据的变化,使用 event 对象的 newValue 属性来获取最新的结果值,event.newValue 属性的返回值总是可以被相信的。

————

02.02. Windows 8 的 IE10 会因为完整性设置导致出错

问题描述:https://stackoverflow.com/que...,在 Windows 8 的 IE10 中,如果相关的用户配置文件中,文件夹的"完整性"设置有问题(可能是是系统清理器导致的),那 localStorage 就可能会操作失败,错误消息是 SCRIPT5: Access is denied

解决方案:问题描述的页面有详细的解决方法,但由于是需要用户在自己的系统中进行修复操作,所以实际上并没有什么意义,因为普通用户哪里会去解决这种问题,对于前端开发者而言,这是系统级别的问题,在浏览器的层面上根本无法解决,所以说即使你的代码没有问题,也不见得就不会报错,所以最稳妥的做法,就是做好容错处理,将所有操作都放到 try…catch 中执行,避免出错后代码被卡住。

————

02.03. 在 Safari 中存储大量数据会导致浏览器被卡住

问题描述:https://bugs.webkit.org/show_...,MacOS 和 IOS 的 Safari,连续存储大量数据时会被卡住,无法响应。

解决方案:这个问题似乎在 2016 年时已经被修复了,XJ 在 Safari(MacOS12.1) 和 Safari(IOS12.2) 中测试都没法复现这 BUG,所以 XJ 也没有什么方案能解决它,只能是尽量避免这种连续操作大额数据的情况,实际上操作大额数据在 IE11 中有 BUG,后面会再提到。

————

02.04. window 的 Storage 事件在 IE 中是完全错误的

问题描述:首先是 IE 的 Storage 事件会在当前页面也触发,按照标准,事件不该在操作数据的页面被触发,这可能导致多个窗口问题,iframe 也可能会受到影响,其次是 IE11 中 Storage 事件的 newValue 会等于 oldValue,按照标准应该返回新值才对。

解决方案:第一个问题可通过标记符来解决,为每个页面创建标记符,保存数据时将标记符和结果值组成对象,用 JSON.stringify() 转成 JSON 格式字符串再保存,之后获取数据时再用 JSON.parse() 解析数据,判断到数据中的标记符等于当前页面的标记符,就表示事件是当前页操作引发的,就不要响应 Storage 事件,实际上你还得改造 removeItem()clear(),因为这两个方法无法携带数据,标记符也就无法传递,所以在执行这两个方法之前,得先执行 setItem() 模拟 removeItem()clear(),更多细节可参考 StackOverflowxj.storage 插件,第二个问题既 IE11 的 newValueoldValue 相等的 BUG,XJ 在 Windows10 的 IE11 中实测后没能复现,也许是后期的 IE11 进行补丁更新已经修复了这个问题,XJ 暂时没什么解决的方案,期待其他其他开发者的补充。

————

02.05. IE 无法保存一些 Ascii 编码 < 32 的控制字符

问题描述:IE 不支持存储编码低于 x20< 32 的 ASCII 字符,这些都是控制字符,遭遇时会报 SCRIPT87: 参数无效 错误。

解决方案:在保存数据前先检测浏览器,如果是 IE,那就使用 replace(/[\u0001-\u001F]/g, '') 消除控制字符串,或者是使用特定字符代替这个控制字符存入,等获取时再替换回去,实际上使用 JSON.stringify() 格式化要保存的数据,也能够解决这个字符的问题。

————

02.06. IE 无法在 file 的协议下使用 Storage 的存储

问题描述:IE 在 file 协议下打开有 Storage 操作的 html 文件会报错,localStoragesessionStorage 都为 undefined

解决方案:将页面放到服务器,使用 http 或 https 协议读取,或是将代码复制到 JSRunCodePen 等支持在线运行的环境下执行。

————

02.07. IE8/9 在协议或端口不同的情况下数据可被共享

问题描述:按照标准,当页面 URL 的协议或端口或域名不同时,Storage 数据就不能共享,但 IE8/9 无视了协议(http 或 https)和端口的区别,只要主机名既 location.hostname 相同,Storage 的数据就可以被共享,这就有可能产生数据被覆盖或者泄漏的风险。

解决方案:可以在保存数据的时候,把当前页面的协议和端口也跟随数据一并保存下来,在操作数据时对协议和端口进行判断,避免数据的覆盖或泄漏,当然更简单的解决方式是直接无视,因为 IE8/9 实在是太老旧了,目前已经没什么人使用,花力气解决也没什么意义。

————

02.08. 在 IOS5/IOS6 中 Storage 数据可能会出现丢失

问题描述:在 IOS5/IOS6 中,Storage 数据被保存在一个有时会被系统自动清除的位置,也就是说数据随时可能会因为被清除而丢失。

解决方案:任何的时候都要做好数据不存在的容错处理,实际上就算没这 BUG,在使用 Storage 的时候也总是要考虑操作失败的情况。

————

02.09. 浏览器在隐身状态或无痕模式下操作可能会出错

问题描述:https://stackoverflow.com/a/1...,早期的 Safari(MacOS 和 IOS) 和 Android Browser,在隐身状态或无痕模式下并不支持 localStoragesessionStorage,这种情况下可能表现为,这两个对象的方法和属性都是正常的,但是它们的存储空间被设置为 0 MB,也就是说你根本无法往这两个对象中存入任何数据,这种情况下浏览器可能会引发一个 QUOTA_EXCEEDED_ERR 的错误。

解决方案:实际上 XJ 自己做了测试,发现 Safari(MacOS12.1) 和 Safari(IOS12.2) 和 Android Browser(Android7.1) 在隐身模式下都不会出错了,但是这也不能证明这个问题就不会在其他场景下出现,所以任何时候都要考虑 Storage 操作失败的场景,将操作都放在 try…catch 中执行是最稳妥的,出错也不会导致所有 JS 逻辑被中断,更具体的操作细节,可参考 StackOverflow 页面提供的代码。

————

02.10. 不用标准方法保存数据则存储量可能会超过 5MB

问题描述:http://dev-test.nemikor.com/w...,除了标准的 setItem() 方法之外,我们其实还可以用中括号表示法如 localStorage[key] 来设置键值对以保存数据,但不少浏览器在用中括号设置键值对时,不会强制执行 localStoragesessionStorage 的 5MB 配额,也就是说即使被额度已经超出,也可以存下而不报错,但页面刷新后值就会丢失,因为超出存储上限。

解决方案:尽量用 setItem() 这些标准方法来操作,很多科普文章也会有这样的建议,虽然往往他们自己也不知道为什么要这样做。

————

02.11. IE9 用数字作键值和中括号表示法操作可能出错

问题描述:http://dev-test.nemikor.com/w...,如题,XJ 没有 IE9,无法复现,如果你有的话可进入链接页实测一下。

解决方案:之前已经说过,尽量使用标准方法存取数据,不要用中括号操作,其次就是 key 值最好别用纯数字,避免引发奇怪问题。

————

02.12. IE8 的 StorageEvent 事件对象缺失了一些属性

问题描述:IE8 的 Storage 事件的对象,并没有 Storage.key, Storage.oldValue, Storage.newValue, Storage.url 这些属性。

解决方案:将需要的 Storage 数据保存成对象,在触发 Storage 事件后,将结果值和之前保存的那对象比对,来获取缺失的这些属性。

————

02.13. IE 的 Storage 事件对象,属性无值时会返回空

问题描述:IE 的 Storage 事件对象,key, oldValue, newValue 属性在不存在时会返回 '',按标准应返回 null 才对。

解决方案:这问题可和上面第四个问题既 04. window 的 Storage 事件在 IE 中是完全错误的 一起解决,在用 JSON.stringify() 保存标记符和目标值时,可增加一个操作行为的属性,用于记录这事件究竟是什么行为导致的,数据结构是这样的 {id:标记符, act:操作行为, data:目标值},之后在 Storage 事件回调中使用 JSON.parse() 解析数据,判断数据操作的行为,if(act === 'clear')key = oldValue = newValue = nullif(act === 'remove')newValue = nullif(act === 'create')oldValue = null,实际上这个改造难度还是有点大的,如果你嫌操作实在是太麻烦了,不如尝试使用 xj.storage 插件来帮你解决这个问题吧。

————

02.14. IE 的清除数据的方法会重复触发 Storage 事件

问题描述:根据标准,如果 Storage 对象中已经没数据,那调用 clear() 方法就不该触发 Storage 事件,但 IE 不管是否还有数据,调用 clear() 方法时总是会触发事件,唯一值得庆幸的是,用 removeItem() 移除不存在的数据时,IE 不会再次触发事件。

解决方案:改造 clear() 方法,如果判断到当前的环境是 IE 浏览器,那么在执行该方法之前,先使用 localStorage.lengthsessionStorage.length 判断 Storage 对象中是否还有数据,如果 length 属性返回 0 就是没有数据了,那直接 return 即可。

————

02.15. IE 设置了相同结果值时也会触发 Storage 事件

问题描述:根据标准,如果为一个 key 值,设置了一个跟之前相同的 value 值,是不该触发 Storage 事件的,因为结果没变的情况下响应事件也没有意义,但 IE 在这种操作下会触发 Storage 事件,在事件的回调中,event.oldValue === event.newValue

解决方案:改造 setItem() 方法,在设置值之前先进行获取,如果获取的值和设置的值相同,就不要继续了,或是在 Storage 事件回调中检测 event.oldValueevent.newValue 属性,如果这两个属性相等,那么就直接 return 返回,不再继续执行回调了。

————

02.16. IE9 的 sessionStorage 的存储事件触发有异常

问题描述:按照标准,sessionStorage 的操作并不会触发 Storage 事件,因为 sessionStorage 的数据并不会在同源的页面之间共享,唯一的例外是页面中的 iframe 标签,并且这个 iframe 标签的地址和当前页面是同源的,但是 IE9 还有另一种例外,如果用 window.open() 打开了同源的页面,无论打开的页面是以新 Tab 标签页打开,还是以单独新窗口的形式打开的,在 iframe 中进行 sessionStorage 的修改操作或移除操作,在新打开的 Tab 标签页,或者新打开的单独窗口页面中,也会响应 Storage 的事件。

解决方案:这问题是 XJ 在很早以前发现的,现在 XJ 已经没有 IE9 可复现这个问题了,IE10/11 都不会出现这种情况,当时的记录也有些模糊,所以 XJ 对这个 BUG 并不是很肯定,如果 BUG 真的存在,可先拿到 window.open() 方法返回的 window 对象,为这个对象设置一个 preventStorage = [] 属性,将不想让窗口响应的 key 值写入,然后在新打开的窗口页面,在 Storage 事件的回调中,检测到数组中有当前响应事件的 event.key 值,那就不要响应,只是这解决方案 XJ 自己没有实际测试过,所以不一定有效。

————

02.17. IE 在 Storage 事件回调中获取数据可能会出错

问题描述:在 IE 中使用 for 循环执行 10 次的 setItem(),存入的值从 0 到 9 依次递增,并绑定 Storage 事件,那么最后的结果是,事件会被响应 10 次,但会在 10 次 setItem() 操作结束后才响应,在事件回调中用 getItem() 获取数据,总会得到 9。

解决方案:这个问题其实是由异步导致的,按照标准 Storage 的所有操作都应该是同步的,但 IE 却并不是如此,它的事件回调被设置成了异步,这就导致在事件回调中使用 getItem() 获取数据,可能会得到一个错误的结果,如果想得到操作数据那一刻的值,可改用 Storage 事件对象的 event.newValue 属性,这个属性返回的总是操作数据后那一刻数据的最新值,因为回调虽然会被延迟执行,但 storageEvent 事件对象却是在执行 setItem() 后就立即生成的,所以对象上的属性都是那一刻的值,就不会出现不准确的情况。

————

02.18. Safari 的 Storage 事件也会在操作数据页响应

问题描述:https://stackoverflow.com/que...,在上面的第四个问题既 04. window 的 Storage 事件在 IE 中是完全错误的 中有提到,IE 的 Storage 事件会在操作数据的页面也响应,实际上这问题在 2018 年 MacOS 10.14 的 Safari 中也是存在的。

解决方案:参考第四个问题的解决方案,不要用网络上流传的借助 event.url 属性或 document.hasFocus() 方法去判断,前者在多个 Tab 标签页打开了相同地址时就没用了,后者如果其他 Tab 标签页操作了 Storage 数据,当前聚焦页会无法响应 Storage 事件。

————

02.19. 事件对象初始化的 initStorageEvent() 有 BUG

问题描述:initStorageEvent() 方法用于初始化 Storage 事件对象,当我们需要手动触发 Storage 事件时就需要用到它,虽然实际上该方法已不被推荐使用,但它在所有浏览器中始终是能运行的,但它在 Safari(MacOS) 和 Safari(IOS) 和 Android Browser 中存在着一个 BUG,当我们面对 clear() 操作需要将 initStorageEvent() 方法的 key 参数设置为 null 时,该方法会自动将我们传入的 null 转为字符串的 'null',结果就导致 Storage 事件回调中,event.key 不等于 null 而是字符串 'null'

解决方案:如果是 clear() 操作触发的 Storage 事件,那么 event.oldValueevent.newValue 都是等于 null,我们可以根据这两个参数判断 Storage 事件是否为 clear() 操作触发的,如果是则使用 event.key 属性的时候,就得创建变量来使用既 var key = (event.key === 'null' ? null : event.key),为什么要创建一个 key 变量使用?为什么不直接将 event.key 属性修改为 null?那是因为在一些浏览器中,event 事件对象是 readOnly 只读的,无法修改,严格模式下修改只读对象还会报错。

————

02.20. IE11 保存大额数据时 Storage 事件将不会响应

问题描述:https://stackoverflow.com/que...,在 IE11 中 localStorage 保存大额数据时,会出现 Storage 事件不响应的情况,在 StackOverflow 页面写着"大额数据"的临界值是 4282(单位字节),但 XJ 测试却发现不一样,说明临界值在不同环境下是不一样的,甚至是在同个环境下还可能会出现动态变化的情况,并且这个临界值是 event.oldValue 属性和 event.newValue 属性相加的结果,也就是说可能在创建时因为 event.oldValue 属性为 null,所以事件会响应,但之后 event.oldValue 属性和 event.newValue 属性的字节数相加超过临界值了,Storage 事件就不响应了,如果超过了临界值,不单 setItem() 操作不响应,removeItem() 操作也不会响应,但 clear() 操作总是会响应,唯一值得庆幸的是 sessionStorage 的操作并不会出现这种情况。

解决方案:在 StackOverflow 页面也有提到,就是改造 setItem()removeItem() 方法,创建一个中间的代理键值对进行响应,代理键值对保存着被操作的目标键值对的 key 值,由于代理键值对比较小,总是会响应,当响应的时候通过它的值就可以知道是操作了哪个目标,以此来解决事件不响应的情况,实际上 XJ 在 xj.storage 插件中也曾尝试过使用这种方法,但是最后还是放弃了,因为这种方式虽然能解决不响应事件的问题,却无法取得这个大额数据最新的结果值,因为此时的 event.newValue 属性是代理键值对的最新结果值,而在事件回调中使用 getItem() 方法获取大额数据当前的结果值,由于 IE 的事件回调存在异步,所以也是不准确的,在无法得到最新结果值的情况下,即使响应了事件,也没有什么意义,实际上这也是这么多 BUG 中 XJ 唯一一个没有妥善方案能解决的问题。


参考内容

MDN - Web Storage API
MDN - 使用网络存储 API

array_huang - localstorage 必知必会
kidney - localStorage 存满了怎么办?

博客园 : awen - localStorage 变更事件当前页响应新解
Feross Aboukhadijeh - 介绍 HTML5 Hard Disk Filler™ API
dev-test.nemikor - 在线测试浏览器的 Storage 的最大存储量

StackOverflow - 为什么 IE 会在存储数据的窗口也触发 Storage 事件
StackOverflow - Safari(MacOS) 也会在存储数据的窗口触发 Storage 事件
StackOverflow - IE11 在一次性存入大额数据的时候将不会触发 Storage 事件

相关插件 - marcuswestin - store.js
相关插件 - Mozilla - localForage
相关插件 - andris9 - jStorage

XJ.Chen - xj.storage

你可能感兴趣的:(前端javascript)