localStorage操作指北

localStorage提供了持久化的本地存储能力,但是由于标准设计年代久远,(getItem的签名是06年4月16日提交的),导致使用并不十分便利。在实际的开发当中,我们还需要解决2个问题:

  • 序列化
  • 溢出

序列化

localStorage把序列化/反序列话的职责丢给用户,个人认为是不符合用户使用习惯的,稍微复杂的场景用起来很蛋疼。

后续HTML标准的其他持久存储功能,比如IndexedDB,是自带序列化和反序列化的。而且localStorage 标准最早的草稿里是带序列化/反序列化的,但后来定稿中去掉了,具体原因未知。

localStorage存储的是字符串类型的数据,当使用setItem的时候会调用数据的toString方法,也就是说

1
2
[1, 2] => "1, 2"
{} => "[object Object]"

合理的做法是,存储JSON格式的字符串,并在getItem/setItem自动进行的序列化/反序列化

溢出

localStorage容量有限,为了安全的操作,避免溢出的情况发生,需要解决3个问题:

  • 确定容量大小
  • 如何知道溢出,溢出了之后浏览器的行为
  • 如何确定一份数据将要占用的空间

容量大小

标准当中并没规定具体的容量大小,只规定了用户代理,也就是浏览器必须限制容量,避免被恶意写入。

User agents should limit the total amount of space allowed for storage areas, because hostile authors could otherwise use this feature to exhaust the user’s available disk space.

同时,标准也规定了,当超过容量限制时,浏览器需要提醒用户,询问用户是否同意扩容。

User agents may prompt the user when quotas are reached, allowing the user to grant a site more space. This enables sites to store many user-created documents on the user’s computer, for instance.

显然,主流浏览器并没有按照标准去实现,那我们看看事实标准是怎样的。

localStorage可以存储的容量大小,通常被认为是5MB,但是安卓在上,手Q 、手机QQ浏览器、微信中则是 2.5M 的量级,因此在移动端,本地存储的 SIZE 更加珍贵。可以用这个网站测试localStorage的容量。

溢出了之后浏览器的行为

我们已经提过,标准规定超过容量限制时,浏览器需要提醒用户,询问用户是否同意扩容。但是我没有发现有浏览器是如此实现的。

事实上,当localStorage溢出时,浏览器会抛出一个错误,并且不会存储这份数据,也不会覆盖现有数据。

那么问题来了,这个错误的错误码是什么,各浏览器是否一致呢?

显然,它并不一致。有标准的情况下,各浏览器都有那么多不一致的情况,更别说这个没有标准的事情了。。。

网络上搜索的答案中,最常出现的答案是QUOTA_EXCEEDED_ERR,但是我在chrome当中测试的结果是QuotaExceededError,根据我的实验,和搜索的结果,如下的代码可供参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
try {
localStorage.setItem(key, value)
} catch (e) {
const ERRORCODE = [
'W3CException_DOM_QUOTA_EXCEEDED_ERR',
'QUOTA_EXCEEDED_ERR',
'NS_ERROR_DOM_QUOTA_REACHED',
'QuotaExceededError'
]
if (ERRORCODE.includes(e.name)) {
//
} else {
//
}
}

如何确定一份数据将要占用的空间

上述的一切告诉我们,要尽量避免localStorage存储空间的溢出。所以,当我们存储数据的时候,最好要做到心中有数 —— 这一份数据将会占用多少的空间呢。

已知:将要存储的数据a是string类型

求:a会占用多少空间

解:

js的字符串使用utf-16编码,一个string占用2位,所以长度为n的字符串占用的空间就是n * 2 / 1024 KB

测试:

测试

参考: