Missed the action at this year's Chrome Dev Summit? Catch up with our playlist on YouTube. Watch now.

Progressive Web App 的离线存储

DevTools 中的 PWA
Pokedex Progressive Web App 针对应用状态和 Pokemon 数据集使用 IndexedDB,而对于网址可寻址的资源则使用 Cache API。

在路上时互联网连接会变得不稳定或无法上网,这是离线支持和可靠的性能成为 Progressive Web App 中的常用功能的原因。即使在完美的无线环境中,明智地使用缓存和其他存储技术也可显著改善用户体验。在此博文中,我们将围绕 PWA  的离线数据存储总结一些想法—思考提供有效的离线体验所需的 JSON 负载、图像和常规静态数据。

建议:

我们进入正题,首先介绍针对离线存储数据的建议:

下面介绍基本原理:

上述两个 API 都是异步的(IndexedDB 基于事件的,而 Cache API 基于 Promise)。 它们也使用网页工作线程、窗口和服务工作线程。 IndexedDB 在每个位置都可用。 服务工作线程(和 Cache API)目前在 Chrome、Firefox、Opera 中可用,并正在针对 Edge 进行开发。IndexedDB 的 Promise 包装器隐藏了 IndexedDB 库自带的一些强大但同时也非常复杂的 machinery(例如,事务处理、架构版本)。IndexedDB 将支持 observers,其让您可以轻松实现标签之间的同步。

Safari 10 在其最新的技术预览版中修复了许多长期存在的 IndexedDB 错误。注:一些用户发现 Safari 10 的 IndexedDB 和 PouchDB 存在稳定性问题,并发现其速度有些慢。在对此问题进行更多研究之前,您的情况可能有所不同。请进行测试并提交浏览器错误,以便 @webkit 工作任意和相关的 OSS 库作者可以查看。默认情况下,LocalForage、PouchDB、YDN 和 Lovefield 在 Safari 中使用 WebSQL(因为缺少有效的方法对损坏的 IndexedDB 进行功能测试)。这意味着这些库无需任何额外操作即可在 Safari 10 中使用(只是不直接使用 IndexedDB)。

对于 PWA,您可以缓存静态资源,从而使用 Cache API 编写您的应用 Application Shell(JS/CSS/HTML 文件),并从 IndexedDB 填充离线页面数据。

针对 IndexedDB 的调试支持目前在 Chrome(Application 标签)、Opera、Firefox(Storage Inspector) 和 Safari(请参阅 Storage 标签)中可用。

其他存储机制是怎样的?

Web Storage(例如 LocalStorage 和 SessionStorage)是同步的,不支持网页工作线程,并对大小和类型(仅限字符串)进行限制。 Cookie 具有自身的用途,但它们是同步的,缺少网页工作线程支持,同时对大小进行限制。WebSQL 不具有广泛的浏览器支持,因此不建议使用它。File System API 在 Chrome 以外的任意浏览器上都不受支持。目前正在 File and Directory Entries APIFile API 规范中改进 File API,但该 API 还不够成熟也未完全标准化,因此无法被广泛采用。

我能存储多少数据?

浏览器 限制
Chrome 可用空间 <6%
Firebox 可用空间 <10%
Safari <50MB
IE10 <250MB

在 Chrome 和 Opera 中,按照源(而不是 API)进行存储。这两个存储机制都将存储数据,直到达到浏览器配额。应用可以使用 Quota Management API 检查它们目前使用了多少配额。 在 Chrome 中,应用最多可使用 6% 的磁盘空间。在 Firefox 中,应用最多可使用 10% 的可用磁盘空间,但在存储 50MB 数据后将提示用户进行更多存储请求。 在 Mobile Safari 中,应用最多可使用 50MB 存储空间,而 Safari 桌面版不限制存储空间的使用(并在达到 5MB 后进行提示)。IE10+ 最多可存储 250MB,并在存储 10MB 后提示用户。 PouchDB 跟踪 IDB 存储行为。

如何了解我的应用目前使用了多少存储空间?

在 Chrome 中,您可以使用 Quota Management API 查询目前使用的存储空间大小,以及应用可使用多少空间。更新的 Storage Quota Estimate API 尝试通过支持 Promise,让用户更容易了解源目前使用了多少配额。

缓存逐出是如何工作的?

浏览器 逐出政策
Chrome 在 Chrome 耗尽空间后采用 LRU 策略
Firebox 在整个磁盘已装满时采用 LRU 策略
Safari 无逐出
Edge 无逐出

根据源的需求为源提供空间量。此可用空间在所有形式的源存储(IndexedDB、Cache API、localStorage 等)中共享。提供的空间量未指定,具体容量因设备和存储条件而异。

如果网络存储容量低,则 UA 将清除存储以提供可用的空间。这会损害离线响应能力,因此,最近更新的存储规范定义了“持久化”和“尽力而为”策略,默认策略是“尽力而为”。“尽力而为”指的是在不干扰用户的情况下可以清除存储,但对于长期和/或关键数据而言持久性较差。IndexedDB 和 Cache API 目前都属于“尽力而为”类别。

“持久化”存储在存储容量低时不会自动清除。用户需要手动清除此存储(通过浏览器设置)。 Chrome 一直在来源试用版中试验对持久化存储的支持,最新消息表明将在 Chrome 55 中发布对持久化存储的支持。

当前和未来的离线存储运行

如果您对离线存储感兴趣,则要注意下面取得的成就。

离线存储并没有多神奇,了解底层 API 对您大有帮助,让您可充分利用我们现在提供的 API。无论您是否愿意直接使用这些 API 还是使用一个抽象库,都需要花些时间熟悉您的选项。

希望本指南将帮助您设计一个离线体验,让您的 PWA 大放光彩!✨

背景阅读

实用资源

  • sw-toolbox(针对动态/运行时请求的离线缓存)

  • sw-precache(针对静态资产/Application Shell 的离线预缓存

  • Webpack 用户可以直接使用上面的资源或 offline-plugin

值得关注的 IndexedDB 库

在此我要感谢 Nolan Lawson、Joshua Bell (这篇文章的主要灵感来自于他在 Open Web Storage 方面的工作和 BlinkOn 演讲)、Jake Archibald、Dru Knox 以及之前致力于网络存储空间的其他人。