HTML5 之 Application Cache™

1. Application Cache 简介

1.1. 什么是 Application Cache

HTML5 引入了应用程序缓存,这意味着 web 应用可进行缓存,并可在没有因特网连接时进行访问。

应用程序缓存为应用带来三个优势:

  • 离线浏览 - 用户可在应用离线时使用它们
  • 速度 - 已缓存资源加载得更快
  • 减少服务器负载 - 浏览器将只从服务器下载更新过或更改过的资源

1.2. 应用缓存原理

HTML5 的离线存储是基于一个 manifest 文件(缓存清单文件,后缀为 .appcache)的缓存机制(不是存储技术),通过这个文件上的清单解析离线存储资源,这些资源就会像 cookie 一样被存储了下来。之后当网络在处于离线状态时,浏览器会通过被离线存储的数据进行页面展示。

1.3. 使用方法

  • manifest 文件的建议的文件扩展名是:.appcache
  • 首先在文档的 html 标签中设置 manifest 属性,引用 manifest 文件
  • 然后配置 manifest 文件,在 manifest 文件中编写离线存储的资源
  • 此外,必须要在服务器端正确的配置 MIME-type。即 text/cache-manifest

1.4. 浏览器兼容性

Offline Web Applications 浏览器兼容性

2. Manifest 文件

manifest 文件是简单的文本文件,它告知浏览器被缓存的内容(以及不缓存的内容)。

manifest 文件可分为三个部分:

  • CACHE MANIFEST - 在此标题下列出的文件将在首次下载后进行缓存
  • NETWORK - 在此标题下列出的文件需要与服务器的连接,且不会被缓存
  • FALLBACK - 在此标题下列出的文件规定当页面无法访问时的回退页面(比如 404 页面)

3. 简单实例

接下来,用具体实例来看一下如何使用离线缓存。

文件夹目录如下:

文件夹目录

cache.html 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
<!doctype html>
<html manifest="cache.appcache">
<head>
<meta charset="UTF-8">
<title>应用缓存</title>
<link rel="stylesheet" href="cache.css">
<script src="cache.js"></script>
</head>
<body>
<img src="cache.png" alt="cache.png">
</body>
</html>

cache.appcache 代码如下:

1
2
3
4
5
6
7
8
9
CACHE MANIFEST
# v0.0.1
CACHE:
/cache.css
/cache.js
/cache.png

NETWORK:
*

manifest 属性可指向绝对网址或相对路径,但绝对网址必须与相应的网络应用同源。manifest 除了缓存 manifest.appcache 文件所指定的资源外,还必定会缓存当前的 html 页面。可以使用星号来指示所有其他资源/文件都需要因特网连接。

注意:这里的版本号,是我们人为规定的,而非是 manifest 自带的属性,当每一次 html 加载到 manifest 时,会对 manifest 配置文件进行脏检查,当检测到 manifest 文件被修改后,之前的缓存将会被弃用,转而去根据 manifest 文件中配置的新内容进行缓存。

缓存查看
使用 node 或其他方法启动服务后,访问页面之后尝试关闭网络环境,依然能够访问。

缓存查看1

缓存查看2

缓存查看3

4. window.applicationCache

window.applicationCache 对象是对浏览器的应用缓存的编程访问方式。其 status 属性可用于查看缓存的当前状态。

4.1. status 属性值

属性值 含义 描述
0 UNCACHED 无缓存, 即没有与页面相关的应用缓存
1 IDLE 闲置,即应用缓存未得到更新
2 CHECKING 检查中,即正在下载描述文件并检查更新
3 DOWNLOADING 下载中,即应用缓存正在下载描述文件中指定的资源
4 UPDATEREADY 更新完成,所有资源都已下载完毕
5 IDLE 废弃,即应用缓存的描述文件已经不存在了,因此页面无法再访问应用缓存

以下代码使用 status 属性为当前通过网页所加载的文档确定应用程序缓存的状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var oAppCache = window.applicationCache;
var sCacheStatus = "Not supported";
switch (oAppCache.status) {
case 0: // UNCACHED == 0
sCacheStatus = '(UNCACHED) : 无缓存, 即没有与页面相关的应用缓存';
break;
case 1: // IDLE == 1
sCacheStatus = '(IDLE) : 闲置,即应用缓存未得到更新';
break;
case 2: // CHECKING == 2
sCacheStatus = '(CHECKING) : 检查中,即正在下载描述文件并检查更新';
break;
case 3: // DOWNLOADING == 3
sCacheStatus = '(DOWNLOADING) : 下载中,即应用缓存正在下载描述文件';
break;
case 4: // UPDATEREADY == 4
sCacheStatus = '(UPDATEREADY) : 更新完成,所有资源都已下载完毕';
break;
case 5: // OBSOLETE == 5
sCacheStatus = '(IDLE) : 废弃,即应用缓存的描述文件已经不存在了,因此页面无法再访问应用缓存';
break;
default:
sCacheStatus = '(UKNOWN) : CACHE STATUS ';
break;
}

4.2 APPCACHE 事件

浏览器会对下载进度、应用缓存更新和错误状态等情况触发相应事件。

事件 描述
checking 每当应用程序载入的时候,都会检查该清单文件,也总会首先触发checking事件。
noupdate 如果没有改动,同时应用程序也已经缓存了noupdate事件被触发,整个过程结束。
downloading 如果还未缓存应用程序,或者清单文件有改动,那么浏览器会下载并缓存清单中的所有资源 ,触发downloading事件,同时意味着下载过程开始。
progress 在下载过程中会间断性触发progress事件,通常是在每个文件下载完毕的时候。
cached 下载完成并且首次将应用程序下载到缓存中时,浏览器会触发cached事件。
updateready 当下载完成并将缓存中的应用程序更新后,浏览器会触发updaterady事件。
error 如果浏览器处于离线状态,检查清单列表失败,则会触发error事件,当一个未缓存的应用程序引用一个不存在的清单文件,也会触发此事件。
obsolete 如果一个缓存的应用程序引用一个不存在的清单文件,会触发obsolete,同时将应用从缓存中移除之后不会从缓存而是通过网络加载资。

以下代码段为每种缓存事件类型设置了事件监听器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function handleCacheEvent(e) {
console.log('对应操作');
}

function handleCacheError(e) {
console.log('Error: Cache failed to update!');
};
//在浏览器为应用缓存查找更新时触发
oAppCache.addEventListener('checking', handleCacheEvent, false);
//在检查描述文件发现文件无变化时触发
oAppCache.addEventListener('noupdate', handleCacheEvent, false);
// 在开始下载应用缓存资源时触发
oAppCache.addEventListener('downloading', handleCacheEvent, false);
//在文件下载应用缓存的过程中持续不断地下载地触发
oAppCache.addEventListener('progress', handleCacheEvent, false);
//在应用缓存完整可用时触发
oAppCache.addEventListener('cached', handleCacheEvent, false);
//在页面新的应用缓存下载完毕触发
oAppCache.addEventListener('updateready', function () {
oAppCache.swapCache();// 更新本地缓存
location.reload(); //重新加载页面页面
}, false);
//在检查更新或下载资源期间发送错误时触发
oAppCache.addEventListener('error', handleCacheError, false);
//缓存清单不存在时触发
oAppCache.addEventListener('obsolete', handleCacheEvent, false);

5. 更新缓存

一旦应用被缓存,它就会保持缓存直到发生下列情况:

  • 用户清空浏览器缓存
  • manifest 文件被修改
  • 由程序来更新应用缓存

以 “#” 开头的是注释行,但也可满足其他用途。应用的缓存会在其 manifest 文件更改时被更新。如果您编辑了一幅图片,或者修改了一个 JavaScript 函数,这些改变都不会被重新缓存。更新注释行中的日期和版本号是一种使浏览器重新缓存文件的办法。

由程序来更新应用缓存:

1
2
3
4
oAppCache.addEventListener('updateready', function(){
oAppCache.swapCache();// 更新本地缓存
location.reload(); //重新加载页面页面
}, false);

6. 注意事项

  • 更新清单中列出的某个文件并不意味着浏览器会重新缓存该资源,清单文件本身必须进行更改。
  • 浏览器对缓存数据的容量限制可能不太一样(某些浏览器设置的限制是每个站点 5MB)。
  • 如果manifest文件,或者内部列举的某一个文件不能正常下载,整个更新过程都将失败,浏览器继续全部使用老的缓存。
  • 引用 manifest 的 html 必须与 manifest 文件同源,在同一个域下。FALLBACK 中的资源必须和 manifest 文件同源。
  • 浏览器会自动缓存引用 manifest 文件的 HTML 文件,这就导致如果改了 HTML 内容,也需要更新 manifest 文件版本或者由程序来更新应用缓存才能做到更新。
  • 若遇到如此报错 “Application Cache Error event: Manifest fetch failed (404)” ,其原因是 manifest 文件需要正确的配置 MIME-type(描述该消息的媒体类型),即 “text/cache-manifest” ,必须在服务器端进行配置。不同服务器配置方式不一样。

在tomcat服务器中的conf/web.xml中添加:

1
2
3
4
<mime-mapping>
<extension>manifest</extension>
<mime-type>text/cache-manifest</mime-type>
</mime-mapping>

7. 与传统浏览器缓存区别

  • 离线缓存是针对整个应用,浏览器缓存是单个文件。
  • 离线缓存断网了还是可以打开页面,浏览器缓存不行。
  • 离线缓存可以主动通知浏览器更新资源。