HTML5/offline

From HTML5 Chinese Interest Group Wiki
Jump to: navigation, search

离线Web应用程序

简介

此章节不具有规范性

为了使用户在他们的网络不可用时(如,当他们外出旅行到一个没有ISP覆盖的地区)仍然可以在web应用和文档中进行交互操作,我们可以为此提供一个manifest,用它列举出那些我们的web应用在脱机工作时需要用到的文件清单,用户的浏览器将按此清单复制其中的文件到本地,以供用户离线时使用。

为了对它进行阐述,我们来看一个简单的”时钟“应用,它由"clock.html","clock.css"和"clock.js"三个文件组成。

在我们添加manifest之前,我们来看看这3个文件,它们大概是这样的:

<!-- clock.html -->
<!DOCTYPE HTML>
<html>
 <head>
  <title>Clock</title>
  <script src="clock.js"></script>
  <link rel="stylesheet" href="clock.css">
 </head>
 <body>
  <p>The time is: <output id="clock"></output></p>
 </body>
</html>

/* clock.css */
output { font: 2em sans-serif; }

/* clock.js */
setTimeout(function () {
    document.getElementById('clock').value = new Date();
}, 1000);

如果用户在离线时尝试访问"clock.html"页面,user agent(除非它在本地有缓存)将返回一个失败的错误。

为了让此情形变得可能,我们可以转而为这三个文件提供一份manifest清单:

CACHE MANIFEST
clock.html
clock.css
clock.js

接着,在这个HTML文件中,我们来做一些小改变,来使那份manifest清单(这份清单文件必须是一个text/cache-manifest的存在)链接到这个应用中:

<!-- clock.html -->
<!DOCTYPE HTML>
<html manifest="clock.appcache">
 <head>
  <title>Clock</title>
  <script src="clock.js"></script>
  <link rel="stylesheet" href="clock.css">
 </head>
 <body>
  <p>The time is: <output id="clock"></output></p>
 </body>
</html>

现在,如果用户再去访问这个页面,他的浏览器将会缓存那些文件,即便用户离线,它们仍将有效。

注:我们鼓励大家将主要的页面包含在manifest清单中,然而,实际上,如果你的页面引用了一份manifest清单,那么,这个页面哪怕没有出现在任何manifest中,也会被自动缓存起来
注:HTTP的cache头和通过TLS服务的(加密的https:)缓存页面限制会被manifest覆盖,因此,在user agent更新它们的应用缓存之前,这些页面将不会过期,并且,通过TLS服务的应用也能够在离线时工作
事件摘要

本章节不具有规范性

当用户访问一个声明了manifest的页面,浏览器会尝试更新缓存。它会遍历这份清单,如果发现该清单自上一次访问后发生了改变,它将重新下载此manifest上列出的资源并重新缓存它们。

在这个过程中,在ApplicationCache对象上会触发一系列的事件,来使脚本保持缓存更新的状态,以便用户可以得到适当地通知。这些事件如下:

事件名称 接口 何时触发 下一个事件
checking Event 当user agent检查更新时,或第一次下载manifest清单时,它往往会第一个被触发 noupdate,downloading,obsolete,error
noupdate Event Manifest清单没有变化 这将是最后一个被触发的事件
downloading Event User agent发现manifest清单有更新,或第一次下载清单上列出的资源 progress,error,cached,updateready
progress ProgressEvent User agent正在下载manifest清单上列出的资源 progress,error,cached,updateready
cached Event Manifest清单上列出的资源都已被下载,且已被应用程序所缓存 这将是最后一个被触发的事件
updateready Event Manifest清单上列出的资源都已被重新下载,script脚本可以通过swapCache()来切换到新的缓存 这将是最后一个被触发的事件
obsolete Event Manifest清单文件返回404或410页面时,应用程序将删除缓存 这将是最后一个被触发的事件
error Event Manifest返回404或401时,应用程序放弃尝试缓存 这将是最后一个被触发的事件
Manifest没有变化,但页面所引用的manifest可能下载失败了
遍历manifest清单上列出的资源时发生了致命错误
Manifest在应用程序进行更新时发生了改变 User agent将在瞬间再次尝试遍历该清单文件

应用程序缓存

应用程序缓存(application cache)是一组由一些缓存资源组成的集合:

每个应用程序缓存(application cache)都有一个完整性标记(completeness flag),其状态为complete或incomplete。


应用程序缓存组(application cache group)就是一组应用程序缓存(application cache),它们由manifest资源的绝对URL(absolute URL)进行识别,用来填充该组中的缓存。

Application cache总是以后来创建的做为新的(newer),换句话说,application caches在一个application cache group中是按时间先后排序的。

application cache group中,只有最新的application cache完整性标记(completeness flag)值为“不完整”的(incomplete);其他的都为“完整的”(complete)。

每个应用程序缓存组(application cache group)都有一个更新状态(update status),其值为以下其中一种:idle, checking, downloading

符合的应用程序缓存(relevant application cache)是在该缓存组(group)最新的(newest)且被标记为“已完成”(complete)的那个application cache

每个应用程序缓存组(application cache group)都有一个未定的主体项目清单(list of pending master entries)。在该清单中的每一项都由一个资源和一个对应的Document对象组成。它们用于在应用缓存下载过程(application cache download process)中确认新的主体项目是否被缓存,即使在它们已经被下载,且应用程序缓存组(application cache group)应用缓存下载过程(application cache download process)已经执行时。

应用程序缓存组(application cache group)可以被标记为作废的(obsolete),即在检查已存在的application cache group时,必须忽略它们。


缓存宿主(cache host)是一个Document对象或是一个SharedWorkerGlobalScope对象,它可以与一个application cache关联。[WEBWORKERS]

Document对象在初始时并未与application cache关联,而是在一个较早的页面加载过程中,当进到in the parser过程,在navigation这块,由cache selection引发,从而使得它们进行关联。

SharedWorkerGlobalScope对象在创建之后可以与一个application cache进行关联。[WEBWORKERS]

每个缓存宿主(cache host)都有一个与之关联的ApplicationCache对象。


在不同的应用程序缓存组(application cache group)中的诸多application cache,可以包含相同的资源,比如,如果该缓存清单指向到那些资源,如果user agent要从符合的应用程序缓存(relevant application caches)清单中选择一个应用程序缓存(select an application cache),它必须使用那些用户最期望的资源,考虑以下因素:

  • 哪些应用程序缓存是最近被更新的
  • 哪些应用程序缓存是用来列出那些用户决定需要检查的新资源,且
  • 哪些应用程序缓存是用户偏好的

匹配备用命名空间(matches a fallback namespace)的URL,如果存在一个符合的应用程序缓存(relevant application caches),它的manifest清单的URL与某个请求的URL同源(same origin),且,该请求的URL有一个前缀匹配(prefix match)备用命名空间(fallback namespace)。如果多个备用命名空间匹配到了同一个URL,那么,最长的那条会是最终匹配的。一个URL在寻找备用命名空间的时候,一次可以匹配到多个应用程序缓存,但在每个缓存中,它只能匹配一个命名空间。

如果一个manifest:http://example.com/app1/manifest

中申明了如下备用命名空间:http://example.com/resources/images ,用户在访问HTTP://EXAMPLE.COM:80/resources/images/cat.png 的时候,user agent将通过http://example.com/app1/manifest

决定它的应用程序缓存,因为它包含一个与请求URL匹配的命名空间。

缓存清单语法

Manifest清单示例

本章节不具有规范性

此缓存清单请求要被缓存的两张图片和一个css样式文件以及一个在网络白名单中的CGI脚本。
CACHE MANIFEST
# 上面这行是必须的

# 这是一行注释
# 在这个文件中的任何地方都可以添加
# 它们全部都会被忽略
  # 在注释之前可以有空格
  # 但必须是在单行前

# 空行也会被忽略

# 这些列在最开始的文件都是需要被缓存的
# 或者是那些列在"CACHE:"里的, "CACHE"头必须写在这些文件之前,如同
# 下面写好的那样
images/sound-icon.png
images/background.png
# 注意,每个文件必须单独一行

# 在线白名单中出现的这个文件,它不会被缓存,并且,
# 对该文件的引用,将绕过缓存,总是会
# 从网络中获取目标(或在用户离线时,尝试从网路上获取)
NETWORK:
comm.cgi

# 这是另一块要缓存的文件,这次只有一个css文件
CACHE:
style/default.css

我们也可以书写成这样:

CACHE MANIFEST
NETWORK:
comm.cgi
CACHE:
style/default.css
images/sound-icon.png
images/background.png
离线应用程序缓存清单可以使用绝对路径或绝对URL地址:
CACHE MANIFEST

/main/home
/main/app.js
/settings/home
/settings/app.js
http://img.example.com/logo.png
http://img.example.com/check.png
http://img.example.com/cross.png
下面的清单定义了一个捕捉所有(catch-all)错误的页面,它会在用户离线时被显示出来。它同时也指定在线白名单通配符标记(online whitelist wildcard flag)为开启(open)状态,即,在访问其他站点资源的时候不会被阻塞。(在相同站点的资源已经不会被阻塞了,因为有捕捉所有(catch-all)的备用命名空间)

只要站点上所有的页面引用了这个缓存清单,它们将全部从本地缓存中取得如同它们实际上被读取一样,随后,那些被命中的同名页面,会立即从缓存中加载,直到缓存清单发生了改变,否则,那些页面将不再从服务端读取。当缓存清单发生改变时,所有的文件都将被重新下载。

子资源,如css样式表,图片等等,无论如何,只能通过常规的HTTP缓存语义进行缓存。

CACHE MANIFEST
FALLBACK:
/ /offline.html
NETWORK:
*
写缓存清单

Manifest文件必须是一个MIME typetext/cache-manifest类型的存在。所有MIME typetext/cache-manifest的文件,必须遵循应用程序缓存清单的语法,就像本章节所描述的那样。

应用程序缓存清单是一个文本文件,采用UTF-8编码方式。文件数据是基于“行”的。换行必须表现为一对U+000A的换行符(LF)与U+000D的回车符(CR)或是一对U+000D的回车符(CR)和U+000A的换行符(LR)。[RFC3629]

注:这是对RFC2046的有意违背(willful violation),因为它要求所有 text/* 类型的文本只得遵循CRLF换行符。无论如何,这种需求已经是过时的;通常情况下,使用CR,LF和CRLF的换行符是被支持的,不过的确在有时候,有些文本编辑器不支持CRLF的换行符。[RFC2046]

应用程序缓存清单文件的第一行必须由此构成:"CACHE"字符串,然后是一个U+0020的空格,接着是字符串"MANIFEST",后面跟着一个U+0020的空格,或是一个U+0009的tab制表符,然后是一个U+000A的换行符(LF)或是一个U+000D的回车符。第一行之前,也可以是一个U+FEFF的字节顺序标记符(BOM)。如果在第一行发现了其他任何文本,它都会被忽略。

接下去如果有其他的行的话,它们必须是以下其中的一种:

空行
空行必须只能由零个或多个U+0020的空格和U+0009的tab制表符组成。
注释
注释行必须由此构成:零个或多个U+0020的空格和U+0009的tab制表符,接着是一个U+0023的数字记号符(#),然后是零个或多个非U+000A的换行符(LF)和U+000D的回车(CR)的字符。
注:注释必须有它们自己的行,如果它们出现在一个有URL的行内,"#"会被误认为是该地址片段标识符的一部分。
段落主题
段落主题会改变当前区域(的作用范围),下面是3种段落主题:
CACHE:
切换到明示区域
FALLBACK:
切换到备用区域
NETWORK:
切换到在线白名单区域

段落主题行,必须由零个或多个U+0020的空格和U+0009的TAB制表符,加上一个出现在上面的3个段落主题名字之一(包括U+003A的冒号字符),后面跟着零个或多个U+0020的空格和U+0009的TAB制表符组成。

有意思的是,在默认情况下,当前区域(的作用范围)是明示区域(explicit section)

当前区域的数据
数据行的格式必须依赖于当前区域(的作用范围)。

如果当前区域为明示区域(explicit section)时,数据行必须由零个或多个U+0020的空格和U+0009的TAB制表符,加上一个有效的URL(valid URL)用于标识除当前缓存清单以外的资源,后面跟着零个或多个U+0020的空格和U+0009的TAB制表符组成。

如果当前区域为备用区域(fallback section)时,数据行必须由零个或多个U+0020的空格和U+0009的TAB制表符,加上一个有效的URL(valid URL)用于标识除当前缓存清单以外的资源,后面跟着零个或多个U+0020的空格和U+0009的TAB制表符,接着又是一个有效的URL(valid URL)用于标识除当前缓存清单以外的资源,最后跟着零个或多个U+0020的空格和U+0009的TAB制表符组成。

如果当前区域为在线白名单区域(online whitelist section)时,数据行必须由零个或多个U+0020的空格和U+0009的TAB制表符,加上一个有效的URL(valid URL)用于标识除当前缓存清单以外的资源或是一个单独的U+002A的星号字符(*),后面跟着零个或多个U+0020的空格和U+0009的TAB制表符组成。

在缓存清单文件中,可能包含多个区块,有些区块的内容也可能为空。

如果缓存清单的访问协议(<scheme>)https:或是另外一种数据加密传输的协议,那么在明示区域(explicit section)中的URLs必须与该缓存清单同源(same origin)

备用区域中,备用命名空间(fallback namespaces)要与一个备用页面的URLs进行关联,并且,命名空间本身需要在备用区域中给出,作为数据行中第一个URL,相应的备用页面的URL跟在后面作为第二个URL。所有其他需要被缓存的页面都应该列到明示区域中。

备用命名空间备用项目必须与当前缓存清单同源

同一个备用命名空间绝对不能重复出现。

User agent送入到在线白名单的命名空间,必须全部在在线白名单区域(online whitelist sections)中列出(那些可能需要与服务端进行交互的页面)。如果要指定所有的URLs都自动进入白名单,可以通过指定一个U+002A的星号符(*)来匹配所有的URLs。

编写缓存清单的时候,不应该让白名单中的一个命名空间包括其中的另一个命名空间,因为它们都采用前缀匹配(prefix match)

相对URLs必须是相对当前缓存清单的URL而言的。所有的这些URLs必须与当前缓存清单使用相同的协议(<scheme>)(不论是明示的还是暗示的)。

缓存清单中的URLs绝对不可以出现片段标识符(也就是说,不能出现U+0023的数字符号"#")

备用命名空间在线白名单中的命名空间都采用前缀匹配模式。

解析缓存清单

User agent在解析缓存清单的时候,必须按照以下步骤进行:

  1. User agent必须对缓存清单文件的字节流进行解码,以解析成UTF-8的格式并进行出错处理(as UTF-8,with error handling)
  2. base URL绝对路径(absolute URL)来表现此缓存清单。
  3. 明示项目(explicit entries)明示URLs(explicit URLs)初始化为一个使用绝对路径(absolute URL)的空列表。
  4. 备用项目(fallback entries)备用URLs(fallback URLs)初始化为一个备用命名空间(fallback namespaces)对应一个绝对路径(absolute URL)的空映射表。
  5. 在线白名单(online whitelist)在线白名单命名空间(online whitelist namespaces)初始化为一个使用绝对路径(absolute URL)的空列表。
  6. 在线白名单通配标识符(online whitelist wildcard flag)为blocking。
  7. "input"为缓存清单文件字节流解码后的文本。
  8. "position""input"的指针,初始化定位到第一个字符。
  9. 如果"position"定位到一个U+FEFF字节顺序标识符(BOM),那么将"position"定位到下一个字符
  10. 如果"position"所在处的字符为"CACHE",接下来是一个U+0020的空格,然后紧跟着"MANIFEST"字样,那么将"postion"定位到它们之后的下一个字符,否则,这就不是一个缓存清单;取消当前的运算规则,在检查魔法签名(magic signature)时返回失败。
  11. 如果"position"所在处的字符即不是U+0020的空格,U+0009的TAB制表符,也不是U+000A的换行符,U+000D的回车符,那么,这不是一个缓存清单;取消当前的运算规则,在检查魔法签名(magic signature)时返回失败。
  12. 这是一个缓存清单文件。当前的运算规则不能在此时返回失败(虽然虚行(bogus lines)可以被忽略)
  13. 收集字符序列(Collect a sequence of characters),U+000A的换行符或U+000D的回车符除外,忽略这些字符(第一行中,签名后的所有其他字符,通通忽略)。
  14. "mode"为"explicit"。
  15. start of line:如果"position"已经到了"input"尾,那么跳转到最后一步。否则,收集以下字符序列(collect a sequence of characters):U+000A换行符,U+000D回车符,U+0020空格,U+0009TAB制表符。
  16. 接下来,收集不包括以下字符的字符序列:U+000A换行符,U+000D回车符,令结果为该行(line)
  17. 丢弃所有出现在此行(line)最后的U+0020空格,U+0009TAB制表符。
  18. 如果此行(line)为一个空字符串,跳转到标签:"start of line"。
  19. 如果此行第一个字符是U+0023的数字标记符(#),则跳转到标签:"start of line"。
  20. 如果此行等于"CACHE:"(单词"CACHE"后面跟着一个U+003A的冒号(:)),则令"mode"为"explicit",然后跳转到标签:"start of line"。
  21. 如果此行等于"FALLBACK:"(单词"FALLBACK"后面跟着一个U+003A的冒号(:)),则令"mode"为"fallback",然后跳转到标签:"start of line"。
  22. 如果此行等于"NETWORK:"(单词"NETWORK"后面跟着一个U+003A的冒号(:)),则令"mode"为"whitelist",然后跳转到标签:"start of line"。
  23. 如果此行以U+003A的冒号(:)作为结束,则令"mode"为"unknown",然后跳转到标签:"start of line"。
  24. 这不是一个数据行也或者语法错误。
  25. position指针进入到此行,初始位置为行首。
  26. "tokens"为字符串列表,初始时为空。
  27. "position"还没有移到行尾时:
    1. "current token"为空字符串。
    2. "position"还没有移到行尾,并且,"position"所在处字符即不是U+0020的空格,也不是U+0009的TAB制表符,将指针处字符添加到"current token""position"指针移到"input"中的下一个字符
    3. "current token"添加到"tokens"列表。
    4. "position"还没有移到行尾,并且,"position"所在处字符是一个U+0020的空格,或者是一个U+0009的TAB制表符,"position"指针移到"input"中的下一个字符。
  28. "tokens"处理流程:
    ↪ 如果"mode"为"explicit"

    解析(resolve)tokens中的第一个元素,以base URL为参照;忽略剩下的。

    如果这里失败,跳转到标签:"start of line"。

    如果结果中的绝对URL(absolute URL)中包含一个与当前缓存清单不同的访问协议(<scheme>)(以忽略大小写的ASCII字符进行比较),则跳转到标签:"start of line"。如果当前缓存清单使用https:协议,或其他某种数据加密传输协议,而结果中的绝对URL与它不是同源(same origin),那么,跳转到标签:"start of line"。

    如果结果中的绝对URL包含标识片段(<fragment>),丢弃它。

    将结果中的绝对URL添加到"explicit URLs"中。

    ↪ 如果"mode"为"fallback"

    "part one""tokens"中的第一个表征,令"part tow""tokens"中的第二个表征。

    解析(resolve)"part one""part two",以base URL为参照。

    如果这里失败,跳转到标签:"start of line"。

    如果关联到"part one""part two"绝对URL(absolute URL)与当前缓存清单不同源(same origin),则跳转到标签:"start of line"。

    如果结果中的绝对URL包含标识片段(<fragment>),丢弃它。

    如果关联到"part one""part two"绝对URL(absolute URL)已经作为一个备用命名空间(fallback namespaces)出现在"fallback URLs"映射表中,则跳转到标签:"start of line"。

    否则,将关联到"part one"绝对URL(absolute URL)作为备用命名空间添加到"fallback URLs"映射表中,映射到关联到"part two"绝对URL(absolute URL),它将作为备用项目实体(fallback entry)

    ↪ 如果"mode"为"online whitelist"

    如果"tokens"中的第一项是U+002A的星号符(*),则设定"online whitelist wildcard flag"为"open",然后跳转到标签:"start of line"。

    否则,解析(resolve)"tokens"中的第一项,以base URL为参照;忽略剩下的。

    如果这里失败,跳转到标签:"start of line"。

    如果结果中的绝对URL(absolute URL)中包含一个与当前缓存清单不同的访问协议(<scheme>)(以忽略大小写的ASCII字符进行比较),则跳转到标签:"start of line"。

    如果结果中的绝对URL包含标识片段(<fragment>),丢弃它。

    将结果中的绝对URL添加到"online whitelist namespaces"中。

    ↪ 如果"mode"为"unknown"
    什么都不做,忽略这一行。
  29. 跳转到标签:"start of line"(步进到下一步,直到抵达文件尾)。
  30. 返回"explicit URLs"列表,"fallback URLs"映射表,"online whitelist namespaces""online whitelist wildcard flag"
注:通过manifest属性申明缓存清单的资源(文件),通常可以从缓存中取到,无论该资源是否出现在缓存清单中,甚至,就算它被列在了在线白名单命名空间(online whitelist namespaces)中。

如果某个资源文件被列在了明示区域(explicit section)或是备用区域(fallback section)中的一个备用项目实体(fallback entry),那么,该资源也可以从缓存中读取,不论它是否匹配到了其他的备用命名空间(fallback namespaces)在线白名单命名空间(online whitelist namespaces)的项目实体。

备用命名空间在线白名单命名空间发生覆盖时,在线白名单命名空间具有更高的优先级。

在线白名单通配标识符(online whitelist wildcard flag)会在最后去应用,仅针对那些既不匹配在线白名单命名空间也不匹配备用命名空间且没有列出在明示区域的URLs。

下载或更新应用程序缓存

当user agent被请求开始应用程序缓存下载进程(application cache download process)为一个声称要去标识一个manifest或一个应用程序缓存组application cache group绝对路径(absolute URL),它可能给定一个特别的缓存主机cache host,也可能给定一个主体项目master资源,这时,user agent必须执行以下步骤。它们通常是异步运行的,与事件循环(event loop)任务(tasks)平行。

在这其中的有些步骤中,有些仅在user agent显示缓存进程(shows caching progress)时才会被应用。对此项的支持是可选的。缓存进程UI可以由一个在user agent用户接口中的进度条或信息栏组成,或是一个遮罩弹出提示层,又或是其他的形式。确定的事件会在应用程序缓存下载过程(application cache download process)中被触发而允许脚本无视那些如接口的显示。如此的目的在于,允许web应用程序提供更多的无缝更新机制,隐藏应用缓存机制的用户的技巧。user agent可以为此显示一个独立的用户接口,不过,不推荐在应用程序取消相关事件时显示主要的更新过程通知。

注:这些事件被延时到load事件触发后才被执行

应用程序缓存下载过程(application cache download process)步骤如下:

  1. 可选,等待,直到通过用户授权开始应用程序缓存下载过程(application cache download process),且user agent确认网络可用。这可能包括在用户明确该站点选用缓存前,或者需要向用户询问授权前,什么都不做。在这时,算法规则永远不会被通过。(当前步骤特意为那些运行在有空间限制或隐私高度敏感的user agent环境而设计)
  2. 自动地,为了避免竞态条件(race conditions),需要执行以下子步骤:
    1. 选择合适的子步骤:

      ↪ 如果这些步骤是通过一个绝对路径调用的用来识别一个应用程序缓存清单

      "manifest URL"为该绝对地址(absolute URL)

      如果通过该缓存清单地址(manifest URL)有找到应用程序缓存组(application cache group),则为此缓存清单地址(manifest URL)创建一个新的应用程序缓存组(application cache group),初始化时,里边没有应用程序缓存。在接下来的算法规则中会创建一个。

      ↪ 如果这些步骤是通过一个应用程序缓存组(application cache group)调用的

      "manifest URL"为该绝对地址(absolute URL),用于识别应用程序缓存组(application cache group)中要更新的缓存清单

      如果应用程序缓存组(application cache group)是被废弃的(obsolete),则取消当前应用程序缓存下载进程(application cache download process)实例。这会发生在有些算法实例在当前的运算等待上面的第一步时发现缓存清单返回404或410的情况下。

    2. "cache group"为通过"manifest URL"识别到的那个应用程序缓存组(application cache group)
    3. 如果这些步骤是被一个主体(master)资源调用的,则添加该资源,顺着该资源的Document,缓存该组的未定的主体项目列表(list of pending master entries)
    4. 如果这些步骤是被一个缓存主机(cache host)调用的,且缓存组(cache group)状态(status)为"checking"或者"downloading",则发起一个post-load的任务队列(queue a post-load task),在缓存主机(cache host)中的应用程序缓存(ApplicationCache)单例中去触发一个可被取消的简单事件(fire a simple event)checking。该事件的默认行为必须是,如果user agent显示缓存进度(shows caching progress),某些类型的用户接口的显示向用户表明,user agent正在检查,看是否能够下载该应用程序。
    5. 如果这些步骤是被一个缓存主机(cache host)调用的,且缓存组(cache group)状态(status)为"downloading",则同样发起一个post-load的任务队列(queue a post-load task),在缓存主机(cache host)中的应用程序缓存(ApplicationCache)单例中去触发一个可被取消的简单事件(fire a simple event)downloading。该事件的默认行为必须是,如果user agent显示缓存进度(shows caching progress),某些类型的用户接口的显示向用户表明,应用程序正在被下载。
    6. 如果缓存组(cache group)状态(status)为"checking"或者"downloading",则取消当前的应用缓存下载过程(application cache download process)实例,作为正在进行的更新。
    7. 缓存组(cache group)状态(status)设置为"checking"。
    8. 为每个缓存主机(cache host)关联的一个缓存组(cache group)中的应用程序缓存(application cache)发起一个post-load的任务队列(queue a post-load task),在缓存主机(cache host)中的应用程序缓存(ApplicationCache)单例中去触发一个可被取消的简单事件(fire a simple event)checking。该事件的默认行为必须是,如果user agent显示缓存进度(shows caching progress),某些类型的用户接口的显示向用户表明,user agent正在检测更新的有效性。
    注:剩下的步骤全部异步执行

    如果缓存组(cache group)内已经有一个应用程序缓存(application cache),则,进入升级尝试(upgrade attempt),否则,进入缓存尝试(cache attempt)

  3. 如果这是一个缓存尝试(cache attempt),则此运算是被一个缓存主机(cache host)调用的;发起一个post-load的任务队列(queue a post-load task),在缓存主机(cache host)中的应用程序缓存(ApplicationCache)单例中去触发一个可被取消的简单事件(fire a simple event)checking。该事件的默认行为必须是,如果user agent显示缓存进度(shows caching progress),某些类型的用户接口的显示向用户表明,user agent正在检测更新的有效性。
  4. 读取缓存清单(fetching the manifest):以同步标识(synchronous flag)的设定来读取来自"manifest URL"的资源,令"manifest"为该资源。

    如果该资源是一个被标记为MIME type缓存清单解析规则(rules for parsing manifests)来解析"manifest",得到一个清单:明示项目(explicit entries)备用项目(fallback entries)和映射到它们的备用命名空间(fallback namespaces)在线白名单项目(online whitelist)和一个在线白名单通配标识符(online whitelist wildcard flag)的值。

    注:使用者代理會無視快取清單的 MIME 類型 ― 總視為 text/cache-manifest。若未來標準支援新的快取清單格式,不同的類型會用檔案簽章(也就是現在格式檔案頂端的"CACHE MANIFEST"字串)來區分。
  5. 如果读取缓存清单(fetching the manifest)返回404或410的响应或类似的(or equivalent)失败,则运行以下子步骤:
    1. 缓存组"cache group"标记为作废的(obsolete)。这个缓存组不在以任何为关联到该缓存组中某个应用程序缓存(application cache)Document对象处理以外的目的而存在。
    2. "task list"为一个空的任务(tasks)列表。
    3. 为关联到缓存组(cache group)应用程序缓存(application cache)的每个缓存主机(cache host),创建一个任务(task),在缓存主机(cache host)中的应用程序缓存(ApplicationCache)单例中去触发一个可被取消的简单事件(fire a simple event)obsolete,它会被加入到任务列表(task list)。该事件的默认行为必须是,如果user agent显示缓存进度(shows caching progress),某些类型的用户接口的显示向用户表明,此应用程序不再能够离线使用。
    4. 为每个在缓存组未定的主体项目列表(list of pending master entries)中的实体,创建一个任务(task),在Document缓存主机(cache host)中的应用程序缓存(ApplicationCache)单例中去触发一个可被取消的简单事件(fire a simple event)error(不是obsolete),如果这里还有一个的话,将它加入到任务列表(task list)。该事件的默认行为必须是,如果user agent显示缓存进度(shows caching progress),某些类型的用户接口的显示向用户表明,user agent为此应用程序离线使用的存储失败了。
    5. 如果缓存组存在一个完整标识(completeness flag)为不完整的(incomplete)应用程序缓存,则丢弃该应用程序缓存
    6. 如果合适的话,移除用户接口表明此缓存正在更新。
    7. 缓存组status为"idle"。
    8. 为任务列表中的每个任务(task)发起一个post-load的任务队列(queue a post-load task)
    9. 取消应用程序缓存下载进程(application cache download process)
  6. 否则,如果在某些情况下提取(fetching)缓存清单失败(如:服务器返回其他的4xx或5xx或其他等同(or equivalent)的响应,或遇到了DNS错误,或连接超时,或用户取消了下载,或魔法签名(magic signature)不合造成的缓存清单解析失败),或服务端返回一个重定向,或目标资源文件的MIME type不是text/cache-manifest类型)Bug.png,则运行缓存失败步骤(cache failure steps)
  7. 如果这是一个升级尝试(upgrade attempt),且,新下载的缓存清单缓存组最新(newest)应用程序缓存(application cache)每字节(byte-for-byte)都一致,或服务端报出一个"304 Not Modified"或等同的(or equivalent)响应时,执行以下子步骤:
    1. "cache"缓存组最新的(newest)应用程序缓存(application cache)
    2. "task list"为一个不包含任务(tasks)的空列表
    3. 为每个缓存组未定的主体项目中的项目,等待对应的资源下载完成或失败。

      如果下载失败(如:连接超时,或用户取消了下载),则创建一个任务(tasks),在Document缓存主机(cache host)中的应用程序缓存(ApplicationCache)单例中触发一个可被取消的简单事件(fire a simple event)error,如果仍然有一个的话,将它加到任务列表(task list)。该事件的默认行为必须是,如果user agent显示缓存进度(shows caching progress),某些类型的用户接口的显示向用户表明,user agent为此应用程序离线使用的存储失败了。

      否则,为此实体关联cacheDocument;如果它不存在,且它的实体归类为主体项目(master entry),则为此实体将资源存储到缓存。如果资源文件的URL中存在片段标识符(<fragment>),它必须从缓存中对应的实体中移除(应用程序缓存绝对不能包含一个片段标识符)。

      注:HTTP缓存规则中,为了应用程序缓存下载处理的目的,诸如:Cache-Control: no-store,这种,都会被忽略。
    4. 缓存组(cache group)中关联到应用程序缓存(application cache)的每个缓存主机(cache host),创建一个任务(task),在缓存主机(cache host)中的应用程序缓存(ApplicationCache)单例中去触发一个可被取消的简单事件(fire a simple event)noupdate,将它加入到任务列表(task list)。该事件的默认行为必须是,如果user agent显示缓存进度(shows caching progress),某些类型的用户接口的显示向用户表明,此应用程序已经是最新的了。
    5. 缓存组的(cache group's)未定的主体项目清单(list of pending master entries)置空。
    6. 如果合适的话,移除用户接口表明此缓存正在更新。
    7. 缓存组状态(status)为idle。
    8. 任务列表中的每个任务(task)发起一个post-load的任务队列(queue a post-load task)
    9. 取消应用程序缓存下载进程(application cache download process)
  8. 最新缓存(new cache)缓存组中最新创建的应用程序缓存(application cache)。将它的完整标识(completeness flag)设置为不完整(incomplete)。
  9. 缓存组未定的主体项目清单(list of pending master entries)中的每个项目,关联Document新缓存(new cache)
  10. 缓存组状态(status)设置为downloading。
  11. 缓存组中关联到应用程序缓存(application cache)的每个缓存主机(cache host)发起一个post-load的任务队列(queue a post-load task),在缓存主机(cache host)中的应用程序缓存(ApplicationCache)单例中去触发一个可被取消的简单事件(fire a simple event)downloading。该事件的默认行为必须是,如果user agent显示缓存进度(shows caching progress),某些类型的用户接口的显示向用户表明,正在下载一个新的版本。
  12. 文件列表(file list)为一个带标识的空URLs列表。
  13. 将所有通过解析manifest时从明示区域(explicit entries)中得到的URLs添加到文件列表(file list)中,并为它们每个都加上"explicit entry"标识。
  14. 将所有通过解析manifest时从备用区域(fallback entries)]]中得到的URLs添加到文件列表(file list)中,并为它们每个都加上"fallback entry"标识。
  15. 如果,这是在进行升级尝试(upgrade attempt),则将缓存组完整标识(completeness flag)为完整(complete)的那些最新的(newest)应用程序缓存(application cache)中的主体项目(master entries)的URLs,添加到文件列表(file list),并为它们每个都加上"master entry"标识。
  16. 如果文件列表(file list)中的任何一个URL出现过1次以上,则将那个URL对应的项目合并到一个,该合并后的项目具有它们之前每个所带的标识。
  17. 文件列表(file list)中的每个URL,执行以下步骤。可能会出现两个或以上的URLs并行执行的情况。
    1. 如果被处理的资源URL标识既不是"explicit entry",也不是"fallback entry",则user agent可以跳过这些URL。
      注:这是打算允许user agents去将缓存中没有列出在manifest缓存清单中的资源设置过期。通常,实现者会被敦促去使用一些方法先为那些较少使用的资源设置过期。
    2. 缓存组中关联到应用程序缓存(application cache)的每个缓存主机(cache host)发起一个post-load的任务队列(queue a post-load task),在缓存主机(cache host)中的应用程序缓存(ApplicationCache)单例中去触发一个不可冒泡的、可被取消的、使用ProgressEvent接口的事件:progresslengthComputable属性必须设置为true,total属性必须设置为文件列表(file list)中文件的数量,loaded属性必须设置为到现在为止,文件列表(file list)中已下载和已跳过的文件数量。该事件的默认行为必须是,如果user agent显示缓存进度(shows caching progress),某些类型的用户接口的显示向用户表明,有个为更新应用程序而准备的文件正在被下载。[PROGRESS]
    3. 在同步标识(synchronous flag)和手动重定向标识(manual redirect flag)都有设置的情况下,从manifest URLURL提取(fetch)资源。如果,这是一个升级尝试(upgrade attempt),则将缓存组最新的(newest)应用程序缓存(application cache)作为HTTP缓存,且,如遵循HTTP缓存语义(如expiration, Etags等等)一般去对待该缓存。user agents也可以有其他一些同样应该被遵循的缓存。
      注:如果存在问题的资源已经因为某些其他的原因而被下载,则,已存在的下载进度有时可以用于此处,按提取(fetching)算法的定义那样
      这里有个例子,可能出现某个大的图片在WEB页面第一次呈现时被下载。它的下载符合页面上的img元素以及列在Manifest清单中的要义。根据提取(fetching)规则,该图片只需下载一次,且它可以同时用作缓存和Web页面渲染。
    4. 如果上一步失败(如:服务器返回4xx或5xx或其他同等(or equivalent)响应,或出现DNS错误,或连接超时,或用户取消下载等等),或服务器返回重定向,则先执行下面的第一步:
      ↪ 如果正在处理的URL带有"explicit entry"或"fallback entry"标识

      执行缓存失败步骤(cache failure steps)

      注:重定向在此是致命的,因为它们既可以表示为网络错误(如:一个强制的网络门户(a captive portal));也可以允许将资源添加到与之真实URLs不同的在网络模式下允许访问的URLs下,而留下孤立的项目;或者允许将资源存储到与真实URLs不同的URLs下。所有这些情况都是很严重的。
      ↪ 如果错误是404或410或其他等同(or equivalent)的HTTP响应
      跳过此资源。它将从缓存中丢弃。
      ↪ 否则
      如果该资源已被提取,则忽略从网络获得的资源,从缓存组完整性标识(completeness flag)为完整(complete)的最新的(newest)应用程序缓存(application cache)中复制资源和其元数据。

      User agents可以向遇到这些错误的用户发出一个警告以协助开发人员了解。

      注:这些规则对列出在Manifest清单中的资源发出致命错误,在有可能发生当有些资源从服务器上删除后,没有发生错误,且幸存的非清单中的资源发生了服务端错误,再将它们从缓存中移除时。
    5. 否则,提取成功。将该资源存储到新缓存(new cache)

      如果user agent不能有效存储该资源(如:引用限制),user agent可以向用户询问或尝试某些手动方式去解决问题(如:自动修剪内容到其他的缓存)。如果问题依旧,user agent必须执行缓存失败步骤(cache failure steps)

    6. 如果正在被处理的URL在文件列表中(file list)带有"explicit entry"标志,则将它归为明示项目(explicit entry)
    7. 如果正在被处理的URL在文件列表中(file list)带有"fallback entry"标志,则将它归为备用项目(fallback entry)
    8. 如果正在被处理的URL在文件列表中(file list)带有"master entry"标志,则将它归为主体项目(master entry)
    9. 作为一种优化,如果此资源是一个HTML或XML文件,且它的根元素是一个设置了manifest属性的html元素,但该属性的值是一个与正在处理的应用程序缓存的manifest URL不一致的值,则user agent应该将此项目标记为外部的(foreign)
  18. 缓存组中关联到应用程序缓存(application cache)的每个缓存主机(cache host)发起一个post-load的任务队列(queue a post-load task),在缓存主机(cache host)中的应用程序缓存(ApplicationCache)单例中去触发一个不可冒泡的、可被取消的、使用ProgressEvent接口的事件:progresslengthComputable属性必须设置为true,totalloaded属性必须设置为文件列表(file list)中文件的数量。该事件的默认行为必须是,如果user agent显示缓存进度(shows caching progress),某些类型的用户接口的显示向用户表明,所有的文件都已下载。[PROGRESS]
  19. 备用命名空间(fallback namespaces)列表,及其映射到的备用项目(fallback entries)URLs,存储到新缓存(new cache)
  20. 在线白名单(online whitelist)中的URLs存储到新缓存
  21. 在线白名单通配标识符(online whitelist wildcard flag)的值存储到新缓存
  22. 缓存组未定主体项目列表(list of pending master entries)中的每一项,等待它们对应的资源完全下载或失败。

    如果下载失败(如:连接超时,或用户取消了下载),则执行以下步骤:

    1. 将此项目从新缓存中断开与Document的关联。
    2. 发起一个post-load的任务队列(queue a post-load task),在Document缓存主机(cache host)中的应用程序缓存(ApplicationCache)单例中触发一个可被取消的简单事件(fire a simple event)error,如果这里还有一个的话。该事件的默认行为必须是,如果user agent显示缓存进度(shows caching progress),某些类型的用户接口的显示向用户表明,user agent为此应用程序离线使用的存储失败了。
    3. 如果这是一个缓存尝试(cache attempt),且,这是缓存组未定主体项目列表(list of pending master entries)中的最后一项,则进一步执行以下子步骤:
      1. 丢弃缓存组(cache group)和它仅有的应用程序缓存(application cache)新缓存(new cache)
      2. 如果合适的话,移除用户接口表明此缓存正在更新。
      3. 终止应用程序缓存下载进度(application cache download process)
    4. 否则,从缓存组未定主体项目列表(list of pending master entries)中移除此项。

    否则,将此项对应的资源存储到新缓存,如果它还没准备好,将它的项目归为主体项目(master entry)

  23. 再次提取缓存清单URL(manifest URL)对应的资源,设置同步标志(synchronous flag),令第二清单(second manifest)为该资源。
  24. 如果上一步因任何原因而失败,或者尝试提取一个目录,或者第二清单(second manifest)缓存清单(manifest)没有每字节(byte-for-byte)都一致,则预约一个具有相同参数的项目算法在一个短暂的延时后返回(return),且执行缓存失败步骤(cache failure steps)
  25. 否则,将缓存清单(manifest)存储到新缓存(new cache),如果它还没准备好,将它的项目归为缓存清单(the manifest)
  26. 新缓存完整性标志(completeness flag)设置为complete。
  27. 任务列表(task list)为空的任务(tasks)列表。
  28. 如果这是一个缓存尝试(cache attempt),则为缓存组中关联到应用程序缓存(application cache)的每个缓存主机(cache host),创建一个任务(task),在缓存主机(cache host)中的应用程序缓存(ApplicationCache)单例中触发一个可被取消的简单事件(fire a simple event)cached。该事件的默认行为必须是,如果user agent显示缓存进度(shows caching progress),某些类型的用户接口的显示向用户表明,此应用程序已被缓存且可以离线使用。

    否则,如果它是升级尝试(upgrade attempt),则为缓存组中关联到应用程序缓存(application cache)的每个缓存主机(cache host),创建一个任务(task),在缓存主机(cache host)中的应用程序缓存(ApplicationCache)单例中触发一个可被取消的简单事件(fire a simple event)updateready。该事件的默认行为必须是,如果user agent显示缓存进度(shows caching progress),某些类型的用户接口的显示向用户表明,新版本已经准备好,在页面重新载入时它将被激活。

  29. 如果合适的话,移除用户接口表明此缓存正在更新。
  30. 缓存组更新状态(update status)设置为idle。
  31. 任务列表中的每个任务(task)发起一个post-load的任务队列(queue a post-load task)

缓存失败步骤(cache failure steps)如下:

  1. 任务列表(task list)为空的任务(tasks)列表。
  2. 缓存组未定的主体项目列表(list of pending master entries)中的每一项,进一步执行以下子步骤。它们可以出现多个项目并行执行的情况。
    1. 等待此项目对应的资源下载完成或失败。
    2. 如果有一个,则解除此项应用程序缓存(application cache)Document的关联。
    3. 创建一个任务(task),在Document缓存主机(cache host)中的应用程序缓存(ApplicationCache)单例中触发一个可被取消的简单事件(fire a simple event)error。该事件的默认行为必须是,如果user agent显示缓存进度(shows caching progress),某些类型的用户接口的显示向用户表明,user agent为此应用程序离线使用的存储失败了。
  3. 缓存组中关联到应用程序缓存(application cache)的每一个缓存主机(cache host),创建一个任务(task),在缓存主机(cache host)中的应用程序缓存(ApplicationCache)单例中触发一个可被取消的简单事件(fire a simple event)error。该事件的默认行为必须是,如果user agent显示缓存进度(shows caching progress),某些类型的用户接口的显示向用户表明,user agent为此应用程序离线使用的存储失败了。
  4. 置空缓存组未定主体项目列表(list of pending master entries)
  5. 如果缓存组有一个完整性(completeness flag)为incomplete的应用程序缓存(application cache),则丢弃此应用程序缓存
  6. 如果合适的话,移除用户接口表明此缓存正在更新。
  7. 缓存组状态(status)为idle。
  8. 如果这是一个缓存尝试(cache attempt),丢弃缓存组算法。
  9. 任务列表中的每个任务(task)发起一个post-load的任务队列(queue a post-load task)
  10. 终止应用程序缓存下载进程(application cache download process)

尝试去提取(fetch)作为应用程序缓存下载进程(application cache download process)中的一部分的资源时,可能会完成缓存击败(cache-defeating)语义,从而去避免一些陈旧的、不一致的中间缓存等问题。


User agents可以在任何时候(不带缓存主机(cache host)),为任何应用程序缓存(application cache),在后台去调用应用程序缓存下载进程(application cache download process)。这将允许user agents甚至可以在没有访问站点的时候去为了更新缓存而去保持缓存预处理。


每个Document都有一个挂起的应用程序缓存处理任务(pending application cache download process tasks)列表,用于延迟由上述算法中触发的事件,直到document的load事件被触发时才去执行。当Document被创建时,此列表必须为空。

当上面的步骤告知一个发起一个post-load的任务队列(queue a post-load task)task,且它是一个在ApplicationCache对象作为目标(target)上触发事件的任务(task),user agent必须适当执行以下步骤:

如果目标Document准备好post-load任务(if target's Document is ready for post-load rasks)
发起(queue)一个task的任务队列。
否则
task添加到目标的(target's)Document挂起的应用程序缓存处理任务(pending application cache download process tasks)

这些任务(tasks)任务源(task source)网络任务源(networking task source)

应用程序缓存的选择算法

選取應用程式緩存演算法Document 參數文件與可選的快取清單 URL 參數快取清單 URL 啟動的時候,使用者代理必須執行以下列表中第一個適用的步驟:

↪ 若快取清單 URL 參數存在 且文件是從應用程式快取載入進來的,且該應用程式快取快取清單 URL 與快取清單 URL「不」一樣
把得到文件所用的應用程式快取對應的項目標記為外來的

重新啟動目前的瀏覽過程(跳到瀏覽演算法最頂端),取消第一次載入時對瀏覽器發生的任何改變(若啟動新頁面造成工作狀態歷史更新的步驟在本選取應用程式緩存演算法執行完成「之後」才發生,則可以確保這些改變未發生,但本規範不要求這個行為)。

注:因為瀏覽器不會在瀏覽過程使用「外來的」項目,瀏覽器不會再一次載入相同的資源。

為了讓應用程式順利開發,使用者代理可告知使用者快取清單與文件本身的後設資料不一致的情形。

↪ 若文件是從應用程式快取載入來的,且該應用程式快取仍存在(還未作廢
連結文件與解析出文件所用的來源應用程式快取。在背景以該應用程式快取應用程序緩存組與作為快取宿主文件呼叫應用程式下載過程
↪ 若文件是從 HTTP GET 或同等情形載入進來且快取清單 URL 存在,又快取清單 URL文件的來源相同
在背景以緩存清單 URL、作為快取宿主文件與作為主體資源的文件的來源資源呼叫應用程式下載過程
↪ 否則
文件不與任何應用程式快取連結。

快取清單 URL 存在,為了讓應用程式順利開發,使用者代理可告訴使用者該 URL 已被忽略。

網路模型的更動

快取宿主與一個完整標記為「complete」的應用程式快取相連的這段時間,所有與快取宿主相關但是不是為了子瀏覽上下文的資源載入過程必須經過以下步驟而不是直接啟動資源協定對應的的機制:

  1. 若資源不是以 HTTP GET 或同等機制獲取,又或資源的 URL 有跟應用程式快取快取清單協定(<scheme>),則以正常方式獲取該資源並退出這些步驟。
  2. 若資源的 URL 是應用程式快取一個主體項目快取清單明確項目備用項目其一,則從快取裡取得資源(而不進行獲取)並退出這些步驟。
  3. 應用程式快取裡有一個與資源的 URL 相同來源線上白名單條目,且該條目與資源的 URL 前輟批配,則以正常方式獲取該資源並退出這些步驟。
  4. 若資源的 URL 與快取清單的 URL 來源相同應用程式快取裡有一個與資源的 URL 前輟批配備用命名空間 f,則:

    以正常方式獲取該資源。若結果為往另一個來源的重定向、4xx 或 5xx 狀態或等價狀態、或是網路錯誤發生(不包含使用者取消下載的情形),則從快取裡取得備用命名空間 f 對應的備用項目。退出這些步驟。

  5. 應用程式快取線上白名單通配符標記為「open」,則以正常方式獲取該資源並退出這些步驟。
  6. 如同網路錯誤發生,視該資源的載入過程失敗。
注:以上演算法確保當線上白名單通配符標記是「blocking」的時候,沒出現在快取清單的資源總是(至少在第一次應用程式快取準備完成之後)會載入失敗,這讓離線應用的測試更為簡單。

过期的应用程序缓存

磁盘空间

应用程序缓存API

浏览器状态