停止使用 localStorage !
medium 优秀文章翻译,也增加自己的一些使用体验。
非标题党!本文标题很明确的想表达对 localStorage 的不推荐。
localStorage 的弊病
2009年 localStorage 诞生,简单来说就是 5MB 的字符串格式的存储。让我拆解下定义中的关键点。
- 字符串集合:它只能存储字符串。如果你想要存储或者检索其他格式数据,你必须进行序列化和反序列化。假如你忘记了这一点,你将会遇到各种各样的网络Bug。例如当你存储 true 和 false 时,你还要注意处理 null、undefined、空字符串等潜在返回值。
- 非结构化数据:JavaScript 结构化克隆算法用于复制复杂的 JavaScript 对象的算法。它通过递归输入对象来构建克隆,同时保持先前访问过的引用的映射,以避免无限遍历循环。postMessage, WebWorkers, IndexedDB, Caches API, BroadcastChannel, Channel Messaging API, MessagePort 和 History API 都是采用的结构化数据! 采用该结构化数据就是为了解决序列化和反序列化 JSON 带来的问题。很遗憾的是 localStorage 并没有更新该特性,并且未来也没有推进的计划。
- 安全妥协:你永远不会在任何持久化存储中保存敏感数据,但是开发者依旧会在 localStorage 中保存 Session IDs,JWTs、API keys 等敏感信息。这是个常见的安全隐患,你可以在 window.localStorage 中随意查阅。
- 性能:localStorage 的性能相对于之前已经有了很好的优化,但是对于超量事务的并发应用程序来说,其性能瓶颈一样要重点考虑。
- 大小限制:localStorage 有 5MB 的限制,而且可能被浏览器删除。对于现代应用来说,5MB 是很小的容量了,几乎很难存储任何媒体数据。它并不是一成不变的,在一些场景下,浏览器也会主动删除部分持久化存储中的数据,这是个通病,这也是何为常规日志上报会有数据丢失的原因之一。因此有甚至需要主动去管理这部分的数据的生命周期,尽管没人告诉你要做这个。还有个点就是存储剩余容量是无法查询的,因此你无法确定操作是否会以为容量达到上限而无法完整写入。
- WebWorker 无法访问:localStorage 并不是面向未来的API,也不是适用于并放进程中。
- 非原子化:localStorage 不保证并行操作中的原子性,也没有任何锁能够保证正在写入的数据不会被覆盖。
- 无数据隔离:localStorage 仅仅是个字符串的对象,应用下所有数据都被混淆在一起,无法进行数据隔离。
- 无事务:常规数据库都会支持事务操作,也没办法进行分组。所有操作都是同步的、非独立的、无锁定的。
- 同步阻塞操作:localStorage 不是异步的,它会阻塞主进程。频繁的读取甚至会影响动画的流畅性,在移动端设备最为明显
WebSQL 何去何从?
WebSQL 目标是为 Web 提供一个简单的 SQL 数据库接口,但是浏览器支持程度确实不好。
你可能好奇它为啥会被抛弃?
- 单一浏览器厂商实现:WebSQL 主要是 Chrome 和 Safari 实现的,由于 Mozilla 和 Microsoft 不支持,业内开发者几乎不采用它。
- 非 W3C 标准:这个是至关重要的,W3C 在 2010 年将它从标准中移除了。
- 与 IndexedDB 的竞争:IndexedDB 主要获得更多的关注,且被设计成标准的跨浏览器解决方案了。
- 安全问题:一些开发人员和安全专家对WebSQL的安全性表示担忧。他们在很多方面都持怀疑态度,包括缺乏权限控制和SOL风格的漏洞。
最终 IndexedDB 成为浏览器存储的标准,被评价为强壮的、跨浏览器友好。但是大多数经验丰富的开发者都视其为瘟疫,那这种推荐又有什么意义呢?
Cookies 又如何呢?
cookie是1994年由网景公司的网络浏览器程序员卢·蒙图利(Lou Montulli)创建的。
本篇文章的标题实际应该是“停止使用 localStorage 和 Cookie”,但是又不全对,我们应该使用安全的 cookies。
- 4KB体积限制
- 默认会被请求传输:非跨域 HTTP 请求会携带 cookie 数据,假如数据不需要被每个请求传输,就会带来带宽开销,导致网络加载速度变慢。
- 安全隐患:cookie更容易受到XSS的攻击。由于cookie会自动包含在对域的每个请求中,因此它们可能成为恶意脚本的目标。
- 过期:cookie被设计为在给定日期过期。
IndexedDB 呢?
- 更好的性能:IndexedDB 操作是异步的,不和阻塞主进程。API 被设计为了事件驱动的。
- 充足的存储配额:与localStorage的5MB上限相比,IndexedDB提供了更大的存储配额(取决于浏览器、操作系统和可用存储。
- 可靠且结构化数据:Indexed 减少了强制类型转换,并且采用结构化克隆算法,保证数据的完整。
但是你大概并不想直接使用 IndexedDB。
IndexedDB 大概是避免过多依赖的例外。将 IndexedDB 视为后台数据库,你需要的是 ORM 或者 数据库处理程序来进行查询的管理。由于 IndexedDB 糟糕的 API 设计,你更想要一个 IndexedDB 库。
- 基于 Promise
- 更好使用
- 减少样板代码
- 关注于更关键的部分
本文比较推荐 dexie.js 和 idb 两个针对 indexedDB 的封装库,其中 idb 的体积是最小的,仅仅 1.19 KB,并不会给程序带来负担。
总结
本文的口号虽然是“停止使用 localStorage”,但是在这个时代实际是难以实现的,但是我们确实应该朝着这个目标出发。
未来开发者应该从 Promise()、async/await 和结构化数据中或者更加清晰且有意义的知识,而不应该关注为何数字“0”在条件语句中会成为“true”,而不应该愤怒与客户获得 null 的返回值。
由于 IndexedDB 的性能优势,你存储各种类型的数据,甚至可以使用游标来遍历所有对象。基于这种技术,你甚至可以构建客户端的搜索引擎,而不会像 localStorage 那样影响动画渲染。
IndexedDB is commonly described as “low-level” . There’s absolutely nothing low-level about IndexedDB, it’s just an API with an old-style and unfriendly syntax. But that doesn't negate it’s underlying capabilities, hence common library usage.
你并不需要直接使用 API,一个体积很小的封装库可以帮助你规避这些。
来源:juejin.cn/post/7338422591518457871