查看缓存详细情况:chrome://appcache-internals/
缓存更新机制:
web应用的缓存只有在manifest文件被修改的情况下才会被更新,所以如果你只是修改了被缓存的文件,那么用户本地的缓存还是不会被更新的,但是你可以通过修改manifest文件来告诉浏览器需要更新缓存了。利用这点,你可以像上面的例子中那样,写一句这样的注释一个文件版本:
- # wanz app v1
这样写有三个好处:
- 你可以很明确的了解离线web应用的版本
- 通过简单的修改这个版本号就可以轻易的通知浏览器更新
- 你可以配合JavaScript程序来完成缓存更新
正如你看到的,manifest文件有三个节点,它们各自的含义如下:
CACHE:
这个是manifest文件的默认入口,在此入口之后罗列的文件 (或直接写在CACHE MANIFEST后的文件)在它们下载到本地后会被缓存起来
NETWORK:
可选的,在此节后面所罗列的文件是需要访问网络的,即使用户离线访问了也会直接跳过缓存而访问服务器
FALLBACK:
可选的,用来指定资源无法访问时的回调页面。每一行包括两个URI,第一个是资源文件URI,第二个是回调页面URI。
备注:以上描述的这些节是没有先后顺序的,而且在同一个manifest中可以多次出现
到目前为止,你应该了解如何来实现离线文件的存储了,只需要三个步骤:1,配置服务器manifest文件的MIME类型;2,编写manifest文件;3,在页面的html标签的manifest属性中引用写好的manifest文件。
缓存更新方法:
你做到了,即使拔掉网线你也可以访问你制作的页面。于是你开始兴致勃勃的丰富你的页面,修改JavaScript代码和css来实现更炫的页面效果,然后将它们上传到服务器,结果你会发现:即使你刷新页面刷到爆,清除n次历史访问记录都无法看到你要的新的页面效果。那是因为你根本还没有更新html5的离线存储文件。现在的问题是如何更新html5离线缓存?下面的三种情况可以做到:
- 1. 用户清除了离线存储的数据,这个不一定就是清理浏览器历史记录就可以做到的,因为不同浏览器管理离线存储的方式不同。比如Firefox的离线存储数据要到“选项”=>“高级”=>“网络”=>“脱机存储”里才可以清除。
- 2. manifest文件被修改,上面说的,你修改了manifest文件里所罗列的文件也不会更新缓存,而是要替换manifest文件
- 3. 使用JavaScript api编写更新程序
前面两种方式很简单,自己折腾吧。我们来看第三种,首先你需要对相关的api有所了解,详细的前往查看: http://www.whatwg.org/specs/web-apps/current-work/#applicationcache
先简单介绍下ApplicationCache和它的几个重点属性及方法:
JavaScript Code复制内容到剪贴板
1. cache = window . applicationCache
2. //返回应用于当前window对象文档的ApplicationCache对象
3. cache = self . applicationCache
4. //返回应用于当前shared worker的ApplicationCache对象 [shared worker]
5. cache . status
6. //返回当前应用的缓存状态,status有五种无符号短整型值的状态:
7. UNCACHED = 0;
8. IDLE = 1;
9. CHECKING = 2;
10. DOWNLOADING = 3;
11. UPDATEREADY = 4;
12. OBSOLETE = 5;
13. cache . update()
14. //调用当前应用资源下载过程
15. cache . swapCache()
16. //更新到最新的缓存,这个不会使得之前加载的资源突然被重新加载。图片不会重新加载,样式和脚本也不会重新渲染或解析,唯一的变化是在此之后发出请求页面的资源是最新的
applicationCache对象和缓存宿主的关系是一一对应,window对象的applicationCache属性会返回关联window对象的活动文档的applicationCache对象。在获取status属性时,它返回当前applicationCache的状态,它的值有以下几种状态:
C/C++ Code复制内容到剪贴板
1. UNCACHED (数值 0)
2. //此时,ApplicationCache对象的缓存宿主与应用缓存无关联
3. IDLE (数值 1)
4. //应用缓存已经是最新的,并且没有标记为obsolete
5. CHECKING (数值 2)
6. ApplicationCache
7. //对象的缓存宿主已经和一个应用缓存关联,并且该缓存的更新状态是checking
8. DOWNLOADING (数值 3)
9. ApplicationCache
10. //对象的缓存宿主已经和一个应用缓存关联,并且该缓存的更新状态是downloading
11. UPDATEREADY (数值 4)
12. ApplicationCache
13. //对象的缓存宿主已经和一个应用缓存关联,并且该缓存的更新状态是idle,并且没有标记为obsolete,但是缓存不是最新的
14. OBSOLETE
15. //(数值 5)
16. ApplicationCache
17. /对象的缓存宿主已经和一个应用缓存关联,并且该缓存的更新状态是obsolete
如果update方法被调用了,浏览器user agent就必须在后台调用应用缓存下载过程;如果swapCache方法被调用了,浏览器user agent会执行以下步骤:
- 检查ApplicationCache的缓存宿主是否与应用缓存关联
- 让cache成为ApplicationCache对象的缓存宿主关联的应用缓存
- 如果cache的应用缓存组被标记为obsolete,那么就取消cache与ApplicationCache对象的缓存宿主的关联并取消这些步骤,此时所有资源都会从网络中下载而不是从缓存中
- 检查在同一个缓存组中是否存在完成标志为“完成”的应用缓存,并且版本比cache更新
- 让完成标志为“完成”的新cache成为最新的应用缓存
- 取消cache与ApplicationCache对象的缓存宿主的关联并用新cache代替关联
假设你已经写好的离线文件存储的Demo页面,通过下面的代码可以来检查,当前页面缓存的状态:
JavaScript Code复制内容到剪贴板
1. var appCache = window.applicationCache;
2. switch (appCache.status) {
3. case appCache.UNCACHED: // UNCACHED == 0
4. alert( 'UNCACHED');
5. break;
6. case appCache.IDLE: // IDLE == 1
7. alert( 'IDLE');
8. break;
9. case appCache.CHECKING: // CHECKING == 2
10. alert ('CHECKING');
11. break;
12. case appCache.DOWNLOADING: // DOWNLOADING == 3
13. alert( 'DOWNLOADING');
14. break;
15. case appCache.UPDATEREADY: // UPDATEREADY == 5
16. alert ('UPDATEREADY');
17. break;
18. case appCache.OBSOLETE: // OBSOLETE == 5
19. alert ('OBSOLETE');
20. break;
21. default:
22. alert ('UKNOWN CACHE STATUS');
23. break;
24. };
一个更新的实现过程大概是这样的:首先调用applicationCache.update()使得浏览器开始尝试更新,前提是你的manifest文件是更新过的(比如前面所说的,修改了版本号);在applicationCache.status为UPDATEREADY 状态时就可以调用applicationCache.swapCache()来将旧的缓存更新为新的。
JavaScript Code复制内容到剪贴板
1. var appCache = window.applicationCache;
2.
3. appCache.update(); // 开始更新
4.
5. if (appCache.status == window.applicationCache.UPDATEREADY) {
6. appCache.swapCache(); // 得到最新版本缓存列表,并且成功下载资源,更新缓存到最新
7. }
没错,更新过程也可以很简单,但是一个好的应用少不了容错处理,就如Ajax技术一样,你需要对更新过程进行监控,处理各种异常或提示等待状态来使你的应用更强壮,用户体验更好,因此你需要了解applicationCache的更新过程所触发的事件,它们是:onchecking,onerror,onnoupdate,ondownloading,onprogress,onupdateready,oncached和onobsolete。监听事件的代码你应该也都轻车熟路了,假设你要对更新错误进行处理,你可以这样写:
JavaScript Code复制内容到剪贴板
1. var appCache = window.applicationCache;
2.
3. // 请求manifest文件时返回404或410,下载失败
4. // 或manifest文件在下载过程中源文件被修改会触发error事件
5. appCache.addEventListener('error', handleCacheError, false);
6.
7. function handleCacheError(e) {
8. alert('Error: Cache failed to update!');
9. };
不管是manifest文件还是它所罗列的资源文件下载失败,整个更新过程就终止了,浏览器会使用上一个最新的缓存。更多关于事件的内容请前往:http://www.whatwg.org/specs/web-apps/current-work/#event-handlers
经过一段时间的测试,我建议大家在chrome下做实验,因为用firefox的实现就像屎,有这个功能却很臭!,最后献上离线应用的demo一枚:丸子的友邻
源地址:http://hi.baidu.com/jqz880321/item/b9c38d99bf594d805914616a
更新缓存
应用在离线后将保持缓存状态,除非发生以下某种情况:
- 用户清除了浏览器对您网站的数据存储。
- 清单文件经过修改。请注意:更新清单中列出的某个文件并不意味着浏览器会重新缓存该资源。清单文件本身必须进行更改。
- 应用缓存通过编程方式进行更新。
缓存状态
window.applicationCache
对象是对浏览器的应用缓存的编程访问方式。其 status
属性可用于查看缓存的当前状态:
var appCache = window.applicationCache;
switch (appCache.status) {
case appCache.UNCACHED: // UNCACHED == 0
return 'UNCACHED';
break;
case appCache.IDLE: // IDLE == 1
return 'IDLE';
break;
case appCache.CHECKING: // CHECKING == 2
return 'CHECKING';
break;
case appCache.DOWNLOADING: // DOWNLOADING == 3
return 'DOWNLOADING';
break;
case appCache.UPDATEREADY: // UPDATEREADY == 4
return 'UPDATEREADY';
break;
case appCache.OBSOLETE: // OBSOLETE == 5
return 'OBSOLETE';
break;
default:
return 'UKNOWN CACHE STATUS';
break;
};
要以编程方式更新缓存,请先调用 applicationCache.update()
。此操作将尝试更新用户的缓存(前提是已更改清单文件)。最后,当 applicationCache.status
处于 UPDATEREADY
状态时,调用applicationCache.swapCache()
即可将原缓存换成新缓存。
var appCache = window.applicationCache;
appCache.update(); // Attempt to update the user's cache.
...
if (appCache.status == window.applicationCache.UPDATEREADY) {
appCache.swapCache(); // The fetch was successful, swap in the new cache.
}
请注意:以这种方式使用 update()
和 swapCache()
不会向用户提供更新的资源。此流程只是让浏览器检查是否有新的清单、下载指定的更新内容以及重新填充应用缓存。因此,还需要对网页进行两次重新加载才能向用户提供新的内容,其中第一次是获得新的应用缓存,第二次是刷新网页内容。
好消息是,您可以避免重新加载两次的麻烦。要使用户更新到最新版网站,可设置监听器,以监听网页加载时的 updateready
事件:
// Check if a new cache is available on page load.
window.addEventListener('load', function(e) {
window.applicationCache.addEventListener('updateready', function(e) {
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
// Browser downloaded a new app cache.
// Swap it in and reload the page to get the new hotness.
window.applicationCache.swapCache();
if (confirm('A new version of this site is available. Load it?')) {
window.location.reload();
}
} else {
// Manifest didn't changed. Nothing new to server.
}
}, false);
}, false);
APPCACHE 事件
正如您所预期的那样,附加事件会用于监听缓存的状态。浏览器会对下载进度、应用缓存更新和错误状态等情况触发相应事件。以下代码段为每种缓存事件类型设置了事件监听器:
function handleCacheEvent(e) {
//...
}
function handleCacheError(e) {
alert('Error: Cache failed to update!');
};
// Fired after the first cache of the manifest.
appCache.addEventListener('cached', handleCacheEvent, false);
// Checking for an update. Always the first event fired in the sequence.
appCache.addEventListener('checking', handleCacheEvent, false);
// An update was found. The browser is fetching resources.
appCache.addEventListener('downloading', handleCacheEvent, false);
// The manifest returns 404 or 410, the download failed,
// or the manifest changed while the download was in progress.
appCache.addEventListener('error', handleCacheError, false);
// Fired after the first download of the manifest.
appCache.addEventListener('noupdate', handleCacheEvent, false);
// Fired if the manifest file returns a 404 or 410.
// This results in the application cache being deleted.
appCache.addEventListener('obsolete', handleCacheEvent, false);
// Fired for each resource listed in the manifest as it is being fetched.
appCache.addEventListener('progress', handleCacheEvent, false);
// Fired when the manifest resources have been newly redownloaded.
appCache.addEventListener('updateready', handleCacheEvent, false);
如果清单文件或其中指定的资源无法下载,整个更新都将失败。在这种情况下,浏览器将继续使用原应用缓存。
参考
- ApplicationCache API 规范