Progressive Web App 的离线存储

本文转载自 developers.google.com

作者:Addy OsmaniMarc Cohen

原文链接:网页存储概览

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

建议:

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

对于网址可寻址的资源,使用 Cache API(服务工作线程的一部分)。
对于所有其他数据,使用 IndexedDB(具有一个 Promise 包装器)。
下面介绍基本原理:

上述两个 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 以及之前致力于网络存储空间的其他人。