65.9K
CodeProject 正在变化。 阅读更多。
Home

使用HTML5 AppCache和IndexedDB构建离线体验

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (2投票s)

2012年6月8日

CPOL

11分钟阅读

viewsIcon

22506

在本文中,我们将展示如何使用 HTML5 AppCache 和 IndexedDB 来创建运行良好的离线网站和应用。

30 天开发一个 Windows 8 应用

用户希望他们的网站和应用即使在没有网络连接的情况下也能正常工作。随着数据越来越多地存储在云端,开发人员希望能够实现流畅的体验,允许在没有连接的情况下访问数据;当设备与网络断开连接或遇到信号盲点时。

在本文中,我们将展示如何使用以下 HTML5 功能来创建运行良好的离线网站和应用:

  • AppCache 本地存储文件资源,并将其作为 URL 离线访问。
  • IndexedDB 本地存储结构化数据,以便您可以访问和查询它。
  • DOM Storage 本地存储少量文本信息。
  • Offline 事件用于检测您是否连接到网络。

示例:随时随地访问的离线支持

假设您带着从您最喜欢的 美食网站 下载的食谱打印出来去购物,但在市场却找不到一些关键配料。

想象一下,当您在家中使用您的便携式电脑浏览 食谱网站 时,网站的一部分已自动下载以供离线使用。这使您能够将便携式电脑带到商店,访问该网站,并在市场上搜索新食谱。最棒的部分是您可以在连接网络的情况下完成此操作。作为消费者,您会更欣赏该网站,因为它在您需要的时候和地点都能正常工作。

使用食谱网站搜索“蛋糕”一词的离线搜索结果。

作为开发人员,您可以结合使用以下离线技术来实现这些场景: AppCacheIndexedDBDOM StorageWebSockets(或 XHR)。在深入探讨各项技术之前,让我们先了解一下它们的优势。

对于 Metro 风格的应用和网站,离线技术使您能够处理连接故障。想象一下,用户正在填写表单,然后失去了网络连接。您的网站或 Metro 风格的应用应该怎么做?无连接开发思维模式允许您的应用独立于网络连接情况而正常工作。您的应用将能够正常运行。

在更复杂的场景中,网站和应用允许用户创建新内容和存储新数据,即使应用程序完全离线。想象一下 Outlook Web Access (OWA)、Hotmail 或 GMail 在离线状态下无缝工作,就像 Outlook 今天所做的一样。

离线技术还可以通过本地提供缓存资源、预缓存未来信息以及将处理能力从云端(或网络)转移到客户端设备来提高整体性能。您能够本地缓存、本地搜索和本地计算的信息越多,服务器所需资源就越少,用户体验就会越快。

用户对 Metro 风格应用离线运行的期望高于网站离线运行。由于它们是从商店通过独立的包进行部署的,用户期望它们具备某种离线功能(例如游戏、书籍、食谱等)。即使这些应用无法创建或访问新内容,之前的 [i=19]内容也应该可见(例如联系人、会议、订阅源、杂志等)。

使用 AppCache 本地缓存文件资源

AppCache 使您能够创建持久化的本地缓存下载文件资源;这些资源您可以在离线时访问,或在线时用于提高性能。设想一个三岁的孩子使用笔记本电脑从您家网络下载一个交互式网页游戏(KidsBook)。如果应用程序的资源存储在本地,孩子可以在没有网络连接的车里继续玩游戏。

如果 KidsBook 是使用 AppCache 实现的,那么在首次下载游戏时以及之后在断开网络连接时,游戏都会缓存所需的资源(JavaScript、HTML、CSS、音频、视频等)。这使得孩子即使在设备本身没有网络连接的情况下也能保持娱乐。

AppCache 创建流程。

要了解如何使交互式网页游戏能够离线运行,请查看 IE Test Drive 网站 上的 KidsBook 示例。

AppCache 使用清单文件来指定资源 URI,以便缓存网站的内容。缓存发生在浏览器显示网页之后,在后台进行,从而允许下载清单文件中定义的资源。这可以确保资源作为单个事务的单元下载到本地计算机,从而创建本地缓存。如果单个资源下载失败,则不会创建缓存。要更新缓存中存储的内容,请更新服务器上的清单文件。当用户下次访问该网站时,浏览器会将服务器上的清单文件与上次缓存的副本进行比较。如果清单的缓存副本与服务器副本不同,则使用更新的清单文件中定义的内容创建新版本的缓存。

AppCache 还允许 Internet Explorer 和 Metro 风格的应用使用传统的 URL 离线访问缓存的资源。这使您能够将 URL 输入浏览器窗口,并在没有任何网络连接的情况下访问这些信息。此外,离线页面可以使用本地缓存的信息解析 URI。有关代码示例,请参阅 IE10 开发者指南 中的 HTML5 应用程序缓存(“AppCache”) 部分。

总体而言,AppCache 在 HTTP 缓存方面具有一些优势。HTTP 缓存不能保证在清除 TIF(临时 Internet 文件)后缓存的资源仍然可用。此外,HTTP 缓存不能在离线时正确解析 URL。但是,可以通过指定缓存资源的生存期来使用 HTTP 缓存来优化 AppCache 的行为。这将决定在创建本地缓存的新版本时,是从 Web 下载资源还是从缓存复制资源。

Metro 风格的应用可以通过本地缓存 iframe 访问的 Web 资源来受益于 AppCache,这使得该内容可以离线访问。

使用 IndexedDB 本地缓存大型结构化数据

IndexedDB 是一个本地数据库,旨在将 JavaScript 对象存储在本地计算机中,从而实现对对象的快速索引和搜索。前面介绍的 食谱网站 包含一个从父网站提取的十六个食谱的数据库。想象一下使用 RSS feed、WebSocket 或 XHR 连接来定期更新此数据库。这将允许您的用户即使在没有网络连接的情况下也能访问最新的食谱。

IndexedDB 使您能够直接操作和索引 JavaScript 对象。使用 indexedDB 在本地搜索信息的一个优点是,它可以减少您的计算成本,避免强迫您始终在云端进行搜索。这假设您能够保持缓存到本地系统的数据的相关性。

显示存储在本地计算机并通过 IndexedDB 访问的食谱列表。

IndexedDB 是一项围绕 ISAM 数据库概念创建的技术。像许多 Web 平台技术一样,它旨在提供一个可以被建立在其上的各种库抽象使用的低级 API。下表将 IndexedDB 开发概念与来自众所周知的 关系模型 的类似概念进行了比较。

概念 关系数据库 IndexedDB
数据库 数据库 数据库
表格 表包含列和行 objectStore 包含 Javascript 对象和键
查询机制、连接和过滤器 SQL 游标 API、键范围 API 和应用程序代码
事务类型和锁 在 READ_WRITE 事务上,锁可以在数据库、表或行上发生。 在 VERSION_CHANGE 事务上,锁可以在数据库上发生;在 READ_ONLY 和 READ_WRITE 事务上,可以在 objectStores 上发生。没有对象级别的锁定。
事务提交 事务创建是显式的。除非我调用 commit,否则默认会回滚。 事务创建是显式的。除非我调用 abort 或发生未捕获的异常,否则默认会提交。
属性查找 SQL 需要索引才能直接查询对象属性。
记录/数据 范式和单值属性 反范式,并且可以具有多值属性。

使用 IndexedDB 时,您将创建 数据库,其中包含 对象存储(联系人、电子邮件、会议等)。这些对象存储包含您的应用程序所需的 JavaScript 对象(联系人 - 名字、姓氏、地址等)。每个 JavaScript 对象都应该有一个可通过 keyPath 访问的唯一标识符。此外,对象存储还将包含用于查询数据集的 索引(电子邮件 - 主题、日期等)。将使用过滤器通过索引或对象存储上的 KeyRanges 来组织或缩减结果集。

以下代码片段显示了如何从“Library”数据库中读取图书记录。

var oRequestDB = window.indexedDB.open("Library");
oRequestDB.onsuccess = function (event) {
    db1 = oRequestDB.result;
    if (db1.version == 1) {
        txn = db1.transaction(["Books"], IDBTransaction.READ_ONLY);
        var objStoreReq = txn.objectStore("Books");
        var request = objStoreReq.get("Book0");
        request.onsuccess = processGet;
    }
};

对象存储中包含的信息始终在 事务 的上下文中进行读写访问。有 三种类型 的事务:

  • VERSION_CHANGE – 用于创建或更新 object store 和索引。由于 VERSION_CHANGE 事务会锁定整个数据库并阻止并发操作,因此不建议在此类事务中读写数据库记录。
  • READ_WRITE – 允许添加、读取、修改和删除 object store 中包含的记录。
  • READ_ONLY – 允许读取 object store 中包含的记录。

IndexedDB 提供的异步 API 模型利用了许多 Web API(如 XHR)支持的 request/response 模型。请求被提交到本地 IndexedDB 进程,结果由客户端的 onsuccessonerror 事件处理程序处理。此外,没有显式的机制来提交事务。当服务器上没有挂起的请求且客户端上没有挂起的结果时,事务将提交。此外,应用程序需要负责处理异常和错误事件。在许多情况下,如果异常或错误事件未得到处理,事务将被中止。

总而言之,IndexedDB 是一种通过索引查询数据对象的优化机制。它为网站提供了通过游标访问大量相关数据的 API,并通过 KeyRange 对象过滤数据。我们认为开发人员会遵循的模式是拥有一个“主”数据库,其中所有用户记录都存储在云端,还有一个本地 IndexedDB 数据库,其中包含一部分记录,以方便快速搜索和离线数据访问。

使用 DOM Storage 和离线/在线事件本地存储少量文本数据

网站可以使用 DOM Storage 和连接事件来处理少量文本数据并检测不良连接。想象一下一个使用这些技术在离线时跟踪用户得分的游戏。想象一下,当没有网络连接时获得高分会发生什么?网页会挂起或崩溃吗?

由于这些数据是文本性质的,并且不需要太多空间,因此您可以使用 DOM Storage 在本地存储信息,无需网络连接,并在稍后网络可用时上传。DOM Storage 支持比 Cookie 更多的数据,并且不需要数据编码。此外,DOM Storage 不会在每次请求时将数据发送到服务器,并且可以作用域限定为域或会话访问。

使用此技术就像访问 windows.localStorage 对象一样简单。在此对象中,您可以以属性的形式检查或添加名称/值对。以下代码片段显示了如何使用 localStorage 在本地存储游戏得分。

<script type="text/javascript">
    var lStorage;
    function init() {
        if (window.localStorage) {
            lStorage = window.localStorage;
            if (typeof lStorage.score == 'undefined')
                lStorage.score = 0;
            document.getElementById('score').innerHTML = lStorage.score;
        }
    }
    function save() {
        if (lStorage) {
            lStorage.score = getGameScore();
        }
    }
</script>
...
<body onload="init();">
    <p>
        Your last score was: <span id="score">last score insert in init()</span>
    </p>
</body>

此外,offline/online 事件将帮助您检测何时具有网络访问权限,以便您可以将数据推送到服务器。例如,您可以检测何时在线,并使用 WebSockets 或 XHR 从服务器更新数据库。

这就像检查 navigator.onLine 属性的状态一样简单。以下代码显示了如何注册在线和离线事件。

function reportConnectionEvent(e) {
    if (!e) e = window.event;
    if ('online' == e.type) {
        alert('The browser is ONLINE.');
    }
    else if ('offline' == e.type) {
        alert('The browser is OFFLINE.');
    }
}
window.onload = function () {
    status = navigator.onLine; //retrieve connectivity status
    document.body.ononline = reportConnectionEvent;
    document.body.onoffline = reportConnectionEvent;
}

在 Metro 风格的应用中,我们还提供了一个额外的 API,Windows.ApplicationData,它允许您在本地存储更多数据类型,并使它们能够跨多个计算机漫游。

关键在于以连接可能随时消失为出发点来设计您的应用程序或网站,并且您需要能够顺利地处理这种情况。实现一种数据模式,在将信息发送到云端之前先将其本地存储,这将使您能够应对有问题的网络连接。

使用 WebSockets 和 XHR 更新本地数据

对于某些场景,您的客户数据将继续保留在云端,以便可以从任何设备轻松访问。因此,您需要确保缓存的数据保持相关、最新和最新的。为了做到这一点,您需要创建通道来同步云端和您的应用之间的数据。您可以利用 WebSockets 和 XHR 来促进此同步。这要求您将数据打包成可传输的格式(例如 XML 或 JSON),使用 XHR 或 Websockets 将这些资源传输到客户端,然后使用 XML 或 JSON 解析器创建将存储在 IndexedDB 数据库中的 JavaScript 对象。这也可以用于将存储在 DOM Storage 中的信息上传到服务器。

结论

网络连接并不总是可靠的;但是,您的应用需要可靠。利用这些离线技术来预测网络短缺将使您的应用在许多消费者场景和情况下变得更好。此外,您可以通过允许您的网站和 Metro 风格的应用正常运行离线,从而获得巨大的机会来区分自己。这将增加其使用率并为您的服务创造更大的机会。利用此处指定的各种离线技术(AppCache、IndexedDB、DOM Storage 等)在本地缓存尽可能多的信息。

有关更多信息,请查看 BUILD 会议 使用 HTML5 在 Metro 风格的应用和网站中构建离线访问,该会议还描述了 File API 在处理离线场景中的作用。

© . All rights reserved.