TL;DR: 我们必须停止提倡 localStorage
作为存储数据的绝佳机会,因为它性能很差。不幸的是,替代方案的支持程度或实现难度都远远不如。
在网页开发中,你总是会遇到一些看似好得令人难以置信的事情。有时它们确实很好,阻止我们使用它们的原因是我们作为开发者对*所有*事物的谨慎态度。然而,在很多情况下,它们实际上并没有看起来那么好,直到我们用了一段时间之后才发现自己其实“做错了”。
本地存储就是一个这样的例子。存在一个 存储规范(在很多例子中被错误地归因于 HTML5),它有一个极其简单的 API,在发布时被誉为是“cookie 杀手”。要将内容存储在用户的机器上,你只需要访问 navigator.localStorage
(或者如果你不需要将数据存储在当前浏览器会话之外,则访问 sessionStorage
)。
localStorage.setItem( 'outofsight', 'my data' );
console.log( localStorage.getItem( 'outofsight' ) ); // -> 'my data'
这种本地存储解决方案对网页开发者来说具有几个非常诱人的功能。
- 它非常简单。
- 它使用字符串来存储数据,而不是复杂的数据库(你可以使用 JSON 编码来存储更复杂的数据)。
- 它得到了 浏览器的良好支持。
- 它得到了许多公司的认可(并且在 iPhone 发布时被誉为是“惊世之作”)。
一些已知的问题是,没有干净的方法来检测何时达到本地存储的限制,并且没有跨浏览器的办法来请求更多空间。还有一些关于会话和 HTTPS 的 不为人知的问题,但这仅仅是冰山一角。
主要问题:性能糟糕
LocalStorage 还有一些没有很好记录的缺点,当然在“HTML5 教程”中也没有充分地介绍这些缺点。特别是注重性能的开发者强烈反对使用它。
几周前,当我们介绍了使用 localStorage 来 在 localStorage 中存储图像和文件 时,它引发了大量的评论,并在内部邮件列表中引发了更长篇幅的讨论,关于 localStorage
的弊端。主要问题是:
localStorage
本质上是同步的,这意味着当它加载时,它会阻止主文档渲染。localStorage
进行文件 I/O 操作,这意味着它写入你的硬盘驱动器,这可能需要很长时间,具体取决于你的系统执行的操作(索引、病毒扫描等)。- 在开发人员的机器上,这些问题可能看起来微不足道,因为操作系统缓存了这些请求 - 对于网络上的最终用户来说,这可能意味着等待几秒钟,在此期间网站会停滞。
- 为了看起来更流畅,网页浏览器会在第一次请求时将数据加载到内存中 - 如果有很多选项卡这样做,这可能意味着会占用大量内存。
localStorage
是持久化的。如果你不再使用某个服务,或者不再访问某个网站,当你启动浏览器时数据仍然会被加载。
Mozilla 性能团队的 Taras Glek 以及诺基亚的 Andrea Giammarchi 在后续的博客文章中详细地介绍了这个问题。
从本质上讲,这意味着很多文章说你可以使用 localStorage
来提高性能是错误的。
替代方案
当然,浏览器一直都提供了一些存储本地数据的办法,其中一些你可能从未听说过,比如 evercookie(我认为,在“没有现实用途的邪恶天才”因素方面,我最喜欢的是用 force-cached PNG 图像来读取 canvas 中的数据)。在内部讨论中,人们大力提倡使用 IndexedDB 而不是 localStorage
。然后我们 发布了一篇文章,介绍如何在 IndexedDB 中存储图像和文件,并且发现了一些问题 - 大部分问题实际上与易用性和用户交互有关。
- IndexedDB 是一个功能齐全的数据库,它需要像 SQL 数据库一样执行所有步骤来读写数据 - 并没有像
localStorage
那样提供简单的键值层。 - IndexedDB 会向用户请求存储数据的权限,这可能会吓到他们。
- 浏览器的支持程度与
localStorage
完全不同,目前 IndexedDB 支持 IE10、Firefox 和 Chrome,并且它们之间存在实现差异。 - Safari、Opera、iOS、Opera Mobile、Android 浏览器更倾向于使用 WebSQL(这是 另一个标准,它已经被 W3C 正式弃用)。
就像往常一样,当实现之间存在差异时,就会有人提出抽象层来解决这个问题。Parashuram Narasimhan 在这方面做得很好 - 甚至提供了一个 jQuery 插件。但感觉我们作为实现者不得不使用这些工具是错误的。这就像 WebM 与 H264 之间的 HTML5 视频之争,只不过又上演了一次。
现在怎么办?
毫无疑问,真正的数据库解决方案及其异步性质在性能方面是更好的选择。它们也更加成熟,并且没有 localStorage
的那种“捷径 hack”的感觉。另一方面,它们比 localStorage
更难使用,我们已经有了很多使用 localStorage
的解决方案,而要求用户授予我们存储本地文件的权限对于某些实现来说在 UX 方面是不可接受的。
答案是,在用户的机器上存储数据没有简单的解决方案,我们应该停止提倡 localStorage
作为性能提升的手段。我们需要找到一个让所有人都满意,并且不会破坏现有实现的解决方案。这可能很难解决。以下是一些想法:
- 创建一个覆盖
localStorage
API 的 polyfill 库,并将内容存储在 IndexedDB/WebSQL 中?这很脏,并且无法解决用户被要求授予权限的问题。 - 在浏览器中以异步方式实现
localStorage
- 积极地无视规范?(但这可能开创一个危险的先例)。 - 更改
localStorage
规范,使其以异步方式存储,而不是同步存储?我们还可以对其进行扩展,使其具有适当的getStorageSpace
接口,并允许本机 JSON 支持。 - 定义一个新的标准,允许浏览器供应商将新 API 映射到现有支持的 API,以便最适合用例?(
我们需要解决这个问题,因为在本地存储数据的同时牺牲性能是毫无意义的。这是一个很好的例子,说明新的网页标准为我们提供了更多强大的功能,但也让我们面对以前不必处理的问题。随着对操作系统的访问权限越来越大,我们也必须更加谨慎。
关于 Chris Heilmann
HTML5 和开放网页的布道者。让我们来修复这个问题!
124 条评论