HTML5离线应用

Published on 2016 - 09 - 25

通过描述文件缓存资源

离线应用的一项基本技术就是缓存,即下载文件(如网页)并在用户计算机上保存一份副本。有了这份副本,即使计算机不能上网,浏览器也可以使用缓存的文件。

创建离线应用的三个步骤如下。

  • 创建描述文件。

描述文件(manifest file)是一种特殊文件,告诉浏览器保存什么文件,不保存什么文件,以及用什么文件代替其他文件。描述文件中列出的所有需要缓存的内容,构成了所谓的离线应用。

  • 修改网页,引用描述文件。

引用了描述文件,浏览器在请求页面时就会下载描述文件。

  • 配置Web服务器。

这一步最重要,因为Web服务器必须以正确的MIME类型提供描述文件。稍后我们会介绍影响缓存的其他问题。

接下来的几节,我们就分别讲解这几个步骤。

传统缓存与离线应用
对Web开发而言,缓存并非新事物。浏览器经常利用缓存以避免下载相同的文件。毕竟,如果很多网页共用相同的样式表,那为什么每个页面都下载多次呢?不过,浏览器的这种缓存方式与离线应用的缓存方式可不一样。
触发浏览器中传统缓存的机制是Web服务器发送额外的信息,即cache-control 头部,这个信息随同浏览器请求的文件一块发给浏览器。头部信息告诉浏览器是否应该缓存该文件,缓存多长时间再询问Web服务器该文件是否更新过。一般来说,缓存网页的时间比较短,而缓存网页资源(如样式表、图片和脚本)的时间比较长。
相对而言,离线应用由一个单独的文件(即描述文件)控制,也不限定时间。大致来说,它的规则是“如果网页是离线应用的一部分,如果浏览器已经缓存了该应用,如果应用的定义没有改变,那么就使用缓存的网页。”作为Web开发人员,可以声明一些例外,告诉浏览器不缓存某些文件,或者不用某个文件替代另一个文件。但是,不用考虑过期时间和其他一些烦琐的细节。

创建描述文件

描述文件是HTML5离线应用功能的关键所在。描述文件就是一个文本文件,其中列出了需要缓存的文件。

描述文件第一行一定是“CACHE MANIFEST”(全部大写):

CACHE MANIFEST

然后,再列出需要缓存的文件。比如,下面的代码表示缓存两个网页:

CACHE MANIFEST

PersonalityTest.html
PersonalityTest_Score.html

文件中的空格(包括上面的空行)是可选的,可以根据需要添加。

为了离线应用的正常运行,浏览器必须缓存其所需的一切,包括网页和网页用到的资源(脚本、图片、样式表和嵌入的字体)。下面这个示例描述文件列出了所有相关的资源:

CACHE MANIFEST
# pages
PersonalityTest.html
PersonalityTest_Score.html

# styles & scripts
PersonalityTest.css
PersonalityTest.js

# pictures & fonts
Images/emotional_bear.jpg
Fonts/museo_slab_500-webfont.eot
Fonts/museo_slab_500-webfont.woff
Fonts/museo_slab_500-webfont.ttf
Fonts/museo_slab_500-webfont.svg

关于这个文件有两点要注意。首先,以#开头的行是注释,说明下面缓存哪些内容。其次,有些资源位于子目录下(比如emotional_bear.jpg,位于Images文件夹中)。只要这些目录与Web服务器中的目录对应,而且浏览器能够访问到该目录,就可以像这样把它们作为离线应用的一部分缓存下来。

复杂的网页一般都需要很多支持文件,因此描述文件也会很长很复杂。因此,最忌讳的问题是拼写错误,一个文件名写错,就会导致整个离线应用无法运行。不久的将来,Web编辑器等工具可以帮我们减少这种麻烦。它们可以根据选中的网页自动创建描述文件,同时为修改和维护描述文件提供辅助功能。

提示 有时候,可能不必缓存一些很大但又不重要的资源。比如,大照片或大的横幅广告。不过,假如缺少这些文件会影响页面呈现(比如导致错误消息、奇怪的页面空白或布局凌乱),那应该使用JavaScript在用户离线时调整页面。

准备好描述文件后,可以把它保存在网站根目录下,与其他网页放在一起。描述文件的名字可以随便起,但有两个扩展名还是推荐大家使用,一个是.manifest,一个是.appcache。前者看起来比较符合逻辑(比如PersonalityTest.manifest),但却与某些Windows Web服务器(特别是.NET应用使用的ClickOnce部署过程)中使用的文件类型冲突。后者其实也很合适(PersonalityTest.appcache),但不太常见。最重要的还是在Web服务器上进行配置,让它能够认识这两个扩展名。

缓存有没有限制 缓存空间有多大?

不同浏览器对离线应用缓存的限制有很大不同。

移动浏览器就是一个例子。因为移动设备本身空间有限,所以对缓存的限制也比较严苛。在本书写作时,iPad和iPhone中的Safari对离线应用缓存的限制是5 MB。

桌面浏览器的限制也大不一样。Firefox的默认设置是最大50 MB,而浏览器用户可以调高这个上限。(在Firefox菜单中选择“选项”,单击“高级”图标,然后选择“网络”选项卡。)Chrome为离线应用提供的空间只有少得可怜的5 MB,除非你开发Chrome应用(http://code.google.com/chrome/extensions/apps.html),或者使用烦琐的配置hack(http://tinyurl.com/5w83opp)。Chrome开发团队打算将来解除这个限制,让用户自己控制每个站点可用的缓存大小;不过,目前暂时还只能限制为5 MB。

显然,浏览器间的这种不一致性会导致问题。如果你想创建的离线应用需要超过5 MB的空间,那么Firefox没问题,但Chrome就不行。更麻烦的是,Chrome用户每次访问你的站点时,Chrome都会缓存该应用,但只要达到空间限制,已经下载的文件也会被完全删除。你为离线所做的一切都将付之东流,而且Chrome用户必须上网才能使用你的应用。

关键在于,将来的离线应用可能会拥有很多存储空间,而现在则只能以5 MB作为上限。结果呢,通过缓存文件提高性能(把常用的大文件下载并长期保存下来)的想法目前看来似乎有点不切实际。不过,希望这种情况很快能得到改观。

使用描述文件

只是创建描述文件可不行,还必须让浏览器知道它在哪里。换句话说,你得在自己的网页中引用它。为此,要为<html>元素添加manifest属性,将该属性的值设置为描述文件的路径,比如:

<!DOCTYPE html>
<html lang="en" manifest="PersonalityTest.manifest">
...

而且,必须给离线应用包含的每个页面都添加同样的属性。在前面的例子中,也就是要修改两个文件:PersonalityTest.html和PersonalityTest_Score.html。

注意 一个网站可以有任意多个离线应用,每个应用分别有自己的描述文件即可。离线应用也可以使用相同的资源(比如样式表),但必须包含不同的网页。

把描述文件放到Web服务器

测试描述文件的时候需要一些耐心,任何微小的问题都可能导致静默失败,结束缓存过程。同样,在适当的时候也要试试看,看你的离线应用是否真能在不联网的情况下运行。

说到测试,从本地硬盘加载文件当然不行,必须得把应用上传到服务器(或者使用本机运行的测试服务器,比如Windows自带的IIS)。

测试离线应用的步骤如下。

  • 确认已经配置好Web服务器,添加了值为text/cache-manifest的MIME类型,以便正确交付描述文件。

如果Web服务器以其他MIME类型(包括纯文本)交付描述文件,浏览器都会忽略描述文件。

  • 考虑关闭针对描述文件的传统缓存机制。

这样做的原因是,Web服务器可能会告诉浏览器把描述文件缓存一段时间,就像告诉它缓存其他文件一样。这种做法无可厚非,但却可能给测试带来极大的难题。假设你后来又更新了描述文件,但浏览器仍然会使用缓存的旧描述文件,于是离线应用也将继续使用以前缓存的网页。(Firefox特别喜欢使用过时的描述文件,很讨厌。)为了避免这一点,应该配置Web服务器,让它告诉浏览器不要缓存描述文件。

  • 在支持离线应用的浏览器(也就是除IE之外的任何浏览器)中打开网页。

浏览器在打开使用了描述文件的网页时,可能会请求用户的许可,之后再下载文件。移动设备通常会请求用户的许可,因为设备本身的存储空间有限。桌面浏览器则不一定,比如Firefox会(如图1所示),而Chrome和Safari不会。

Firefox会在加载包含描述文件的网页时显示这条消息。单击Allow授权下载并缓存该描述文件中列出的文件。随后再浏览此网页,Firefox会检测描述文件是否有更新,如果有更新则自动下载新文件而不会再请求授权

用户同意之后(或者浏览器没有问),缓存过程就会开始。浏览器会下载描述文件,然后再下载描述文件中列出的所有文件。这个下载过程是在后台进行的,不会影响当前页面。就如同浏览器下载大图片或下载视频一样,同时会显示页面的其他部分。

  • 模拟离线。

如果你测试的是远程服务器,那么断开网络连接。如果是在本地Web服务器(即运行在你的计算机中的服务器)中测试,停止网站。

  • 浏览离线应用中的某个页面,然后刷新。

即使告诉浏览器不要缓存某个页面,有时候它也会缓存,因为只有这样你点击Back按钮才会返回上一页。但在单击Refresh或Reload时,浏览器则会尝试访问Web服务器。如果你请求的是一个常规页面,(由于你已经断网或停掉了网站)那么请求会失败。可是,如果你请求的是离线应用中的一个页面,浏览器则会从缓存中找到该页面,悄悄地代替之前的页面。此时,单击链接可以自由跳转。如果你单击了不属于离线应用的页面,则会看到熟悉的“服务器没有响应”的错误消息。

我的离线应用离线不工作

离线应用功能还不是很稳定,一个小小的错误就会导致它不能工作。如果你按照上面列出的步骤做了,但在尝试访问离线页面时还是看到了“服务器没有响应”的消息,可以试着排除以下常见的问题。

  • 下载描述文件出了问题。如果你没有把描述文件放在正确的位置,或者说浏览器没有找到它,那么出问题是自然的。但是,以正确的MIME类型来提供描述文件也同样重要。
  • 下载描述文件中列出的文件出了问题。比如,描述文件中包含一个不存在的图片。或者,要求浏览器下载Web字体文件,但该字体文件的类型又是Web服务器所不支持的。无论如何,只要浏览器下载一个文件时失败,它也会完全放弃(同时删除已经下载的所有数据)。为避免这个问题,先从简单的描述文件开始尝试,比如只包含一个网页,而不包含其他资源。如果不行,再查看一下Web服务器的日志,看浏览器到底请求了什么资源(这样就能知道是请求哪个文件出错导致了浏览器放弃)。
  • 浏览器缓存了旧的描述文件。浏览器有可能会缓存描述文件(根据传统的Web缓存规则),因此忽略更新的描述文件。如果你发现有些网页的确是被缓存的,但一些新网页却没有被缓存,那就可能是这个原因。解决方案是手工清空浏览器缓存。

更新描述文件

让应用离线工作是要解决的第一个难题。第二个难题是更新离线应用的内容。

就拿前面的例子来说吧,它缓存了两个页面。如果你更新了PersonalityTest.html,打开浏览器,重新加载这个页面,你看见的仍然是原先缓存的那个页面。无论你的计算机目前能否上网,都是如此。问题在于,只要浏览器缓存了应用,那么它就不会向Web服务器请求新内容。浏览器不管你是否更新了服务器上的页面,它只管用自己已经缓存的那个。由于离线应用没有过期一说,所以无论你过多长时间以后再看,就算是几个月以后再看,浏览器照旧还会忽略更新后的页面。

不过,浏览器会检测服务器上的描述文件是否有更新。因此,重新保存一次描述文件,把它放到服务器上,就可以解决这个问题了,对吧?

不一定。要触发浏览器更新缓存的应用,需要同时满足下列要求。

  • 浏览器没有缓存描述文件。如果浏览器在本地缓存了描述文件,它就不会再访问Web服务器去找新描述文件。在是否缓存描述文件这个问题上,不同浏览器有不同的处理方式。有的浏览器(比如Chrome)只要有条件就会检测服务器,看有没有更新的描述文件。但Firefox却遵循着传统的HTTP缓存规则,会将描述文件缓存一段时间。所以,为了减少麻烦,最好是让Web服务器明确告诉浏览器,不要缓存描述文件。
  • 描述文件的保存日期必须是新的。浏览器在检测服务器上的文件时,首先要看文件的最近更新时间。如果不是新保存的描述文件,那浏览器不会下载它。
  • 描述文件中的内容要更新。如果浏览器下载了新描述文件,结果却发现其内容没有变化,它同样会停止更新,而继续使用之前缓存的内容。这一点虽然不太合乎常理,但却很有价值。你想,重新下载一遍本来就已经缓存的内容,既耽误时间又浪费带宽,所以浏览器不在必要时是不会下载的。

如果你一直都在认真领会前面的内容,到这里可能会冒出一个问题来:要是描述文件确实没有什么好改的(因为你并没有添加任何文件),而我又想让浏览器更新缓存内容怎么办(因为原有的文件内容有变化)?这时候,你得稍微修改一下描述文件,让它看起来像是新的一样。为此,最好的办法就是添加注释,比如:

CACHE MANIFEST
# version 1.00.001
# pages
PersonalityTest.html
PersonalityTest_Score.html

# styles & scripts
PersonalityTest.css
PersonalityTest.js

# pictures & fonts
Images/emotional_bear.jpg
Fonts/museo_slab_500-webfont.eot
Fonts/museo_slab_500-webfont.woff
Fonts/museo_slab_500-webfont.ttf
Fonts/museo_slab_500-webfont.svg

等下一次再需要浏览器更新缓存时,只要把这个例子中的版本号改为1.00.002就行了。这样,既可以强制让浏览器更新已有内容,也可以记录自己更新的次数。

更新并不会瞬间完成。浏览器发现新描述文件后,会悄悄地下载所有文件,然后再用新下载的文件代替原来缓存的内容。下次用户再访问同一个页面(或刷新该页面),就会显示新内容。

注意 不能以只更新增量的方式更新离线应用。只要应用中有变化,浏览器就会抛弃所有旧文件,然后重新下载一遍,包括丝毫未改的那些文件。
 

浏览器对离线应用的支持情况

相信大家都已经知道了,除了拖HTML5后腿的IE,所有主流浏览器都支持离线应用。有的浏览器很早就开始支持离线应用了,目前可以确定有Firefox、Chrome和Safari。表1列出了具体版本信息。

要求 IE Firefox Chrome Safari Opera Safari iOS Android
最低版本 3.5 5 4 10.6 2.1 2

可是,不同浏览器支持离线应用的方式却不大一样。最重要的不一样是它们分配给离线应用的存储空间。这个差别非常重要,因为它决定了哪些网站可以做成离线应用,而哪些不能。

有没有让不支持离线应用的浏览器(如IE9)支持它的办法呢?没有什么值得尝试的好办法。不过,这并不妨碍你使用离线应用功能。毕竟,离线应用只是一个补充而已。

不支持离线功能的浏览器照样可以访问你的网站,只要能上网就行。对于那些需要离线浏览的人,比如经常出差的人,他们自己会找一个支持离线功能的浏览器,以备没有网络时使用。

实用缓存技术

到现在为止,我们已经介绍了把一组页面和资源打包成离线应用的方法。期间,我们学习了如何编写和更新描述文件,以及如何让浏览器不要忽视我们的劳动成果。利用这些知识,很容易做出一个简单的离线应用来。可是,要实现复杂一些的站点的离线功能,仅有这些知识还不够。比如,我们想让某些内容在线,而在离线时将它们替换成其他页面,这就涉及如何(在代码中)判断计算机是否处于联网状态。在接下来的几节中,我们就来学习怎样编写更智能的描述文件,怎样通过简单的JavaScript检测设备在线状态。

访问未缓存的文件

经过前面的学习,我们知道浏览器在缓存了某个页面后,它就不会再向Web服务器发送请求,而是直接使用缓存的页面。但你知道吗,浏览器对离线页面的所有资源也持同样的态度,无论它是否缓存了这些资源。

比如,假设有个页面使用了两张图片,标记如下:

<img src="Images/logo.png" alt="Personality quiz">
<img src="Images/emotional_bear.jpg" alt="Sad stuffed bear">

可是,描述文件只要求浏览器缓存了一张图片:

CACHE MANIFEST
PersonalityTest.html
PersonalityTest_Score.html

PersonalityTest.css
PersonalityTest.js

Images/emotional_bear.jpg

有读者认为,浏览器会从缓存中取得emotional_bear.png,然后(在计算机联网的情况下)从Web服务器上取得logo.png。毕竟,过去的经验告诉我们,在从缓存的页面中访问未缓存的页面时,浏览器就会这样做。可是对于离线应用来说,没有这回事儿。事实上,无论什么浏览器,都会从缓存中取得emotional_bear.png,而忽略未缓存的logo.png并显示未找到文件的图标或者一块空白区域,具体显示什么,取决于浏览器。

要想解决这个问题,必须在描述文件中添加一个区块。这个区块的开头冠以“NETWORK:”字样,然后紧跟着一组必须在线访问的页面:

CACHE MANIFEST
PersonalityTest.html
PersonalityTest_Score.html

PersonalityTest.css
PersonalityTest.js
Images/emotional_bear.jpg

NETWORK:
Images/logo.png

这样,在联网时,浏览器才会尝试从Web服务器下载logo.png文件,而在离线时,则会忽略它。

此时,你可能会想:为什么要把不想缓存的文件都给列出来呢?或许是因为缓存空间有限的原因,比如为了不让缓存超过5 MB,你可能会考虑不让浏览器缓存那些大文件。

但更有可能是这些内容不能缓存,比如跟踪脚本或动态生成的广告。此时,最简单的办法是在“NETWORK:”区块中使用一个通配符,即星号(*)。这样浏览器就知道所有未缓存的内容都必须联网访问:

NETWORK:
*

另外,还可以使用星号匹配任意类型的文件(比如,*.jpg匹配所有JPEG图片),或者位于特定服务器上的所有文件(比如,http://www.google-analytics.com/*匹配Google Analytics域中的所有文件)。

注意 既然可以使用通配符,那在缓存文件列表中使用它可以吗?这样不必逐个罗列,就可以缓存一大批文件了。很遗憾,缓存文件列表不支持通配符,因为HTML5规范制定者担心有人会无意中缓存庞大的站点。

添加后备内容

我们知道,利用描述文件可以告诉浏览器哪些文件要缓存,哪些文件要从Web服务器获取。除此之外,描述文件还支持一个“FALLBACK:”区块,这里列出的文件可以根据计算机是否在线而互换。

“FALLBACK:”区块可以在描述文件中的任何地方出现,但要每行列出一对文件来。第一个文件名是在线时使用的文件名,第二个文件名是离线后备文件名。

FALLBACK:
PersonalityScore.html PersonalityScore_offline.html

浏览器会把后备文件(即这里的PersonalityScore_offline.html)下载并缓存起来。不过,只有在不能上网的时候浏览器才会使用这个后备文件。而在能上网的时候,浏览器会照常向Web服务器请求另一个文件(即这里的PersonalityScore.html)。

注意 不必为了让Web应用觉得“离线”而断开网络连接。实际上,关键在于能否访问到服务器,如果服务器没有响应,Web应用就会认为已经离线了。

至于什么时候该使用后备内容,那可能性就多了去了。比如,可以在离线时让浏览器使用一个简单点的页面,其中的脚本与在线页面中的不同,或者使用了更少的资源。后备内容放在哪儿都可以,只要一开始加上“FALLBACK:”就可以:

CACHE MANIFEST
PersonalityTest.html
PersonalityTest_Score.html

PersonalityTest.css

FALLBACK:
PersonalityScore.html PersonalityScore_offline.html
Images/emotional_bear.jpg Images/emotional_bear_small.jpg
PersonalityTest.js PersonalityTest_offline.js

NETWORK:
*

注意 在描述文件中,我们想要缓存的文件位于CACHE区块中。不过,除非你想要在另一个区域之后再列出要缓存的文件,否则不必有意添加这个区块。

后备内容区块也支持通配符匹配。这样就可以创建一个内置的错误页面,比如:

FALLBACK:
/ offline.html

假设有人要请求与离线应用在同一个网站中的页面,但该页面没有在缓存中。如果计算机在线,浏览器就会联系服务器取得该页面。如果计算机不在线,或者无法访问网站,或者根本就没有找到请求的页面,那浏览器会显示缓存的offline.html页面(图4)。

浏览器访问的ImaginaryPage.html不存在,但浏览器却没有更新地址栏,因此用户无从知晓错误页面到底叫什么名字

在前面的例子中,使用一个斜杠(/)表示任意网页可能会让人觉得有点不太对劲儿,因为“NETWORK:”区块的通配符是星号。不过,在有的浏览器(比如Firefox)中,确实可以在后备区块中使用星号,而这就意味着可以将前面的例子重写为这样:

FALLBACK:

* offline.html

除了使用通配符,还可以通过指定子目录来匹配更小范围内的文件:

FALLBACK:
http://www.superAppsOnSteroids.org/paint_app/* offline.html

或者,也可以指定只匹配某些类型的文件:

FALLBACK:
*.jpg missig_picture.jpg

可惜的是,除了Firefox之外,还没有别的浏览器能理解这些语法,至少现在还没有。

检测连接

孰不知,使用JavaScript检测浏览器当前是否在线的一个诀窍,就是利用后备区块。如果你是一位JavaScript老手,可能知道navigator.onLine属性,这个属性能够告诉你浏览器当前是否在线,但不一定准确。onLine属性的问题是,它只真实地反映浏览器“脱机工作”的设置,并不反映计算机是否真的连到了因特网。就算onLine属性能真实反映连接情况,它也不会告诉你浏览器到底是没有连接到Web服务器,还是由于种种原因没有下载到网页。

所以,我们只能利用后备区块,让浏览器根据应用是否在线分别加载相同JavaScript函数的不同版本。为此,要在后备区块中添加如下文件对:

FALLBACK:
online.js offline.js

原始的网页引用online.js:

<!DOCTYPE html>
<html lang="en" manifest="personality.manifest">
<head>
  <meta charset="utf-8">
  <title>...</title>
  <script src="online.js"></script>
  ...

这个JavaScript文件包含着一个非常简单的函数:

function isSiteOnline() {
  return true;
}

如果浏览器没有下载到online.js,就会使用offline.js,后者包含着一个同名函数,但返回值不同:

function isSiteOnline() {
  return false;
}

在原始的网页中,为了知道应用是否在线,检测这个isSiteOnline()函数即可:

var displayStatus = document.getElementById("displayStatus");
if (isSiteOnline()) {
  //(可以运行依赖上网的任务,比如通过XMLHttpRequest连接Web服务器)
  displayStatus.innerHTML = "You are connected and the web server is online.";
}
else {
  //(应用在离线运行,需要隐藏或修改一些内容,或者禁用某些功能)
  displayStatus.innerHTML = "You are running this application offline.";
}

通过JavaScript指定更新

使用相对有限的JavaScript接口可以与离线应用功能交互。这个JavaScript接口就由applicationCache对象定义。

通过applicationCache对象的status属性,可以知道浏览器当前在干什么,是在检测更新的描述文件,还是在下载新文件,抑或在做其他事。这个属性变化很快,也很有用;同样有用的是与不同属性值对应的事件(参见表2),这些事件会在applicationCache的状态变化时触发。

事  件 说  明
onChecking 浏览器在发现网页中的manifest 属性时,会触发这个事件,并向Web服务器请求描述文件
onNoUpdate 如果浏览器已经下载了描述文件,而描述文件并未改变,浏览器就会触发这个事件,然后不再做什么了
onDownloading 浏览器在开始下载描述文件(以及其中列出的文件)之前会触发这个事件。除了第一次下载描述文件时,更新文件时都会触发这个事件
onProgress 下载文件期间,浏览器会不断地触发这个事件,以报告进度
onCached 当新离线应用的所有文件都下载完毕后,会触发这个事件。此后,不会再发生事件
onUpdateReady 这个事件表示已经取得了更新的内容。此时,新内容已经可以使用了,但除非重新加载页面,否则不会在浏览器窗口中出现。此后,不会再发生事件
onError 缓存期间发生任何问题都会触发这个事件。可能是无法连接Web服务器(这种情况下,会把页面切换到离线浏览模式),或者描述文件包含错误的语法,或者缓存的资源不存在。此后,不会再发生事件
onObsolete 在检测更新时,浏览器发现描述文件不存在了,就会触发这个事件。然后,它会清除缓存。下次再加载页面时,浏览器会从Web服务器取得实时、最新的在线版页面

这里面最有用的事件是onUpdateReady,表示浏览器已经下载了新版本的应用。即使新版本已经可以使用了,但浏览器窗口中显示的仍然是旧版本的内容。此时,可以利用这个事件告诉访客刷新页面,浏览新版本的内容,就像桌面应用下载完更新之后所做的那样:

window.onload = function() {

  //给onUpdateReady事件注册事件处理程序
  applicationCache.onupdateready = function() {
    var displayStatus = document.getElementById("displayStatus");
    displayStatus.innerHTML = "There is a new version of this application. " +
      "To load it, refresh the page.";
  }
}

要不,也可以使用window.location.reload()方法,在用户确认后重新加载页面:

window.onload = function() {

  applicationCache.onupdateready = function() {
  if (confirm(
   "A new version of this application is available. Reload now?")) {
      window.location.reload();
    }
  }
}

图5展示了这段代码的运行结果。

如果访客单击OK,应用就会重新加载当前页面,显示更新后的内容(否则,下次再打开这个页面或者刷新页面之后,才会出现新内容)

除了status属性和上述事件之外,applicationCache对象还有两个方法:update()和swapCache()。其中,update()方法的名字有点含糊,实际上调用它只会让浏览器检测是否有新的描述文件。如果有,浏览器就会在后台下载新文件;否则,什么也不做。

虽然浏览器能自动检测更新,但你也可以调用update()方法让它去检测,以便及时发现更新的描述文件。这个方法很适合那些生命期长的Web应用,比如一打开就是一整天的页面。

第二个方法是swapCache(),用于告诉浏览器开始使用新缓存的内容——如果它已经下载完了更新。然而,swapCache()方法不会影响当前显示的页面;要让当前页面显示新内容,必须重新加载它。那swapCache()还有什么用呢?通过切换到新缓存,此后加载的所有内容(比如动态加载的图片),都会从新缓存(而不是旧缓存)中取得。如果处理得好,利用swapCache()既可以让页面访问新内容,又不必强制完全重载(同时也就不会把当前应用重置为初始状态)。但在大多数应用中,使用swapCache()还是弊大于利,有时候会造成混用新、旧缓存的问题。

参考文档