Html5已经被提过很久了,各种新属性出来,人们也都欢呼了一把,今天要讨论的是一个html5的新属性——manifest,可能有很多人已经用过该方法来优化自己的网站了。今天来分享下我们在使用manifest的时候遇到的问题。
1.概念
该特性为HTML5的新特性,能够让web程序指定可以缓存在本地的资源,以及缓存策略,使得程序能够在离线时仍然能够运行,也可以使程序在线时也可以从本地加载资源而不用重新从网络加载。
2.基本写法
要用manifest,就要了解其基本写法
通过在页面的html标签中中引入:
<html manifest=”/static/index/innovation/cache.manifest”>
Cache.manifest的文件写法:
- CACHE MANIFEST
- # v2012 1203v3
- http://m.baidu.com/static/index/i.gif
- http://m.baidu.com/static/hb/hot.gif
- http://m.baidu.com/static/index/logo_index2.png
- NETWORK:
- *
- http://m.baidu.com/su
- http://loc.map.baidu.com/wloc
- http://m.baidu.com/static/tj.gif
第一行一定要写上CACHE MANIFEST,然后注释写后面,以后通过修改注释,来实现manifest的更新。
A.路径写法不支持带端口,所以最好用相对路径吧,要不然线下测试机上开发,有端口不好调试。
B.*号通配符有时候好像并不好使。如果在某些设备上出现问题,可以排查一下是不是这个导致的。
C.#以后的内容虽然是注释,但是不能放到第一行,第一行必须是如上的大写字母。
1.离线后的页面
页面离线后,好处显而易见,页面可以秒开了(启动速度快)。你会感觉页面加载的速度快了很多。但是也有一些问题。
A.页面都离线了,如何更新?首先,你可以修改下manifest文件来更新这个页面,这个我就不介绍了,但是作为文章内容页面离线以后,就会存储在本地了,如果你是一篇文章的话,那么这个文章的内容页就被存下来了,你如果以相同的url去访问,不管你文章里面的数据更新没有,这个离线下来的页面都不会更新了(除非你更新manifest文件)。所以,所有的动态数据,你都得用ajax方式去获取,就像客户端一样,离线的页面应该是一个没有数据的空壳,然后通过ajax去拉去数据填补这个空壳。然后要注意的是,ajax的请求地址,要写到manifest的network中,要不然,你可以试试。
B.页面的参数如何携带?,还是刚才那个问题,文章页的壳如果缓存了,怎么样传数据过来标识这个特点页面呢?比如m.baidu.com/app?a=1&b=2,通常我们用一些参数来标记这个页面,通过参数来渲染页面内容,但是manifest对于上面的方式,会认为不同的参数表示不同的页面。如果你吧内容页做成一个无数据的空壳,这种传参的方式显然不行,好在不一样的hash页面,manifest会认为是同一个页面,比如m.baidu.com/app#detail-111111与m.baidu.com/app#detail-222222会认为和m.baidu.com/app是同一个缓存页面。这样我们就可以通过hash传值了,当然,你也可以通过其它方式传值,比如写入cookie,写入localstorage方式等等。
4.离线页面的更新
网站更新了,如果更新用户本地的离线页面呢?与很多文章中说的一样,先上线你的文件,然后修改一下页面中引入的cache.manifest文件即可,比如修改下注释,修改后,如果再访问页面,就会先去校验manifest时候有更新,如有更新,再次刷新页面的时候,页面就会更新了。
A.长尾问题,就像前面说到的一样,如果你的manifest文件更新了,你访问页面,需要刷新一次,更新的页面才能load进来,那么这样就有一个问题,如果你的后端数据,就是给js ajax接口的数据变化了,你对应的js也修改了。那么你修改manifest上线的时候,第一次开页面,页面就会bug了。再刷一次页面,就好了。那么,这个第一次访问的bug,是我们不想看到的。而且你不能知道用户什么时候第二次再来访问你的页面,所以你的页面一旦使用manifest离线,就像客户端一样,这样就出现了长尾问题。还好,manifest有一些js接口,可以来判断,load更新文件。
B.刷新页面
有了js的api,一切都好办了,我们可以干很多事情了。现在你可以用js来判断页面的状态了,可能你已经想到,判断状态后,可以刷新一下页面,那么,就算数据发生了修改,这种处理方式也是ok的,没错,这样确实解决了问题。你也可以在设置了manifest的页面中加入这些方法,然后修改下文件,看看会触发哪些事件,刷新页面的唯一问题就是页面会闪动一下,这点体验当然是不好的。因此,我们想到了loading页面。
C.Loading页面
制作一个loading页面,用来检测manifest文件有没有更新如果发现有更新,则更新资源,然后再跳到真实的首页。这个实现起来就比较容易了,在loading页面你可以加一些效果,比如加载效果等等,给用户一个预知。让我们看看manifest修改过和没有修改过各种状态的差别。保证你的manifest文件存在有效,如下:
- CACHE MANIFEST
- #test11123aaadfsaasdadffdsfaaaffd
- http://m.baidu.com/static/js/zepto-event-ajax.js
- testb.html
- NETWORK:
- *
Html文件如下:
- <!DOCTYPE html>
- <html manifest=”notes.manifest”>
- <head>
- <title>离线存储demo</title>
- <meta http-equiv=”Content-Type” content=”text/html;charset=UTF-8″>
- </head>
- <body>
- Hello world!
- <script type=”text/javascript” src=”http://m.baidu.com/static/js/zepto-event-ajax.js”></script>
- <script type=”text/javascript”>
- var appCache=window.applicationCache;
- console.log(appCache.status);
- appCache.addEventListener(“obsolete”,function(){
- console.log(“Obsolete,status:”+appCache.status);
- },false);
- appCache.addEventListener(“cached”,function(){
- console.log(“chache,status:”+appCache.status);
- },false);
- appCache.addEventListener(“checking”,function(){
- console.log(“checking,status:”+appCache.status);
- },false);
- appCache.addEventListener(“downloading”,function(){
- console.log(“downloading,status:”+appCache.status);
- },false);
- appCache.addEventListener(‘noupdate’, function(){
- console.log(‘Noupdate,Status:’ + appCache.status);
- }, false);
- appCache.addEventListener(‘updateready’, function(){
- console.log(‘updateready,Status:’ + appCache.status);
- }, false);
- appCache.addEventListener(“error”,function(){
- console.log(“error”);
- },false);
- </script>
- </body>
- </html>
如果页面没有发生变化:那么以上代码会输出:
如果对应的manifest有修改,需要更新文件,那么上面的代码会输出:
如果更新了manifest,会触发downloading和updateready事件。你可以根据这两个事件来处理一些逻辑了,比如在downloading给用户一些提示,正在加载,updateready就跳转到真正的页面,那么这个时候,页面就已经加载好了,就不用再刷新才生效页面了。比如:
- appCache.addEventListener(‘updateready’, function(){
- console.log(‘updateready,Status:’ + appCache.status);
- location.href=”testb.html”;
- }, false);
该页面在loading页面上,其实主要的内容页面在testb.html上。
D.Loading页面的问题
这时,你可能认为,这个不错,解决了所有问题。效果也ok,也没有第一次加载页面可能出错的状况。如果对于一个单页面来说,这样确实没问题了,但是如果你是一个完整的站,问题又来了,你不可能给网站每个页面都加loading,就算每个模版页都用一个loading,如果用户进入了你某个页面,如果把你某个页面存到了桌面快捷方式。那么下次启动,可能还是会挂,必须刷一次页面才能好,所以,你可能想到,整个页面都要通过js去build了……,然后又要保持build页面的js要在页面渲染前发生更改,那么,你可以在每个壳模版页面判断manifest的逻辑,然后动态载入的js,通过动态载入的js来build整个html页面,那么这样就木有bug了,不过这种处理方式确实恶心了,如果你的模版页的html壳更新不多,仅仅会更新里面的js逻辑的话,那你可以在改html壳中动态载入js即可,也可以直接刷一下页面来解决。
但是这毕竟不是一个app,如果你的站点突然接到需求要更新得很频繁,比如一天要更新一次,那么,这个manifest离线的意义就仅仅在于第二次载入的时候可以秒开。除此之外,我也想不到其他好处。然后用户如果一天刚好访问一次的话。这个状态好像还没有不用manifest离线的状态好。那么,我需要把manifest下线……
5.Manifest的回滚与下线
其实,回滚与下线表现上来说,差不多,当然,我这里所提到的回滚,是第一次上线manifest的回滚,一般如果你上线manifest出现了问题,比如造成的线上严重的bug,那么,这是时候,一般公司就会有回滚机制,用以前的代码来覆盖现在的代码。但是你一旦上线了manifest离线存储,回滚就没那么容易了,就是从有manifest的状态到无manifest的状态,其实这点和manifest下线一样。很多人都知道每次更新了静态文件,更新一下manifest多刷两次页面,页面就更新了。如果manifest文件没有了呢,我们还是拿上面的那个页面做测试。
第一次刷新会这样:
第二次再刷新是这样:
删除manifest以后,浏览器校验manifest文件就会返回一个404,那么这时,manifest就会失效,再刷页面,页面就会又开始自动更新了。也不会缓存了,是不是很兴奋。这不是很简单么?删掉manifest文件就能回滚了,就能下线了。不过现在好像404不流行了,如果你删掉了服务器上某个静态文件,服务器会302跳转到一个错误页,那么这时候,你在怎么刷新页面,页面都不会在更新了。悲剧了……用户手机浏览器中的页面再也更新不了了。此时你只能再次更新manifest让其强制更新。可能你还想到,我删除了manifest文件,把html中manifest引用也删除不就行了么。这个也是不行的。浏览器缓存了该地址的离线信息,除非你清除浏览器的缓存,否则这招无效。
所以,如果可以,就可以利用manifest文件404把manifest下掉。
如果这招行不通呢?就是没法返回404。那么你上线manifest的时候就要注意了。前文中提到了loading,那么你得再loading中处理好load manifest文件失效的情况。其实处理方式也很简单,就是跳到本来该跳的页面,然后带上一个参数(前面已经说过,带参数与带hash的区别)也就可以很轻松解决这个问题了,但是需要注意一定,找不到manifest文件,第一次刷新和第二次刷新所触发的事情不一样,第一次会触发obsolete事件,第二次再刷新,就触发error事件,不过这样也好办,我们在这两个事件中,将链接都跳到一个带参数的页面就好了(在error、obsolete中跳到页面带参数,在updateready、noupdate里面直接跳到页面)。所以,利用manifest的js api然后配合删除manifest文件(此时就可以不管页面是不是302或者404了),就可以下线掉manifest文件了,如果用户不清缓存,那段曾经被离线的代码就会起作用,会让用户永远页面带上参数。
- appCache.addEventListener(“downloading”,function(){
- console.log(“downloading,status:”+appCache.status);
- console.log(“downing”);
- },false);
- appCache.addEventListener(‘noupdate’, function(){
- console.log(‘Noupdate,Status:’ + appCache.status);
- location.href=”testb.html”;
- }, false);
- appCache.addEventListener(‘updateready’, function(){
- console.log(‘updateready,Status:’ + appCache.status);
- location.href=”testb.html”;
- }, false);
- appCache.addEventListener(“error”,function(){
- console.log(“error”);
- location.href=”testb.html?a=1″;
- },false);
- appCache.addEventListener(“obsolete”,function(){
- console.log(“Obsolete,status:”+appCache.status);
- location.href=”testb.html?a=2″;
- },false);
5.适用场景小结
上线,下线,回滚,长尾等等问题都考虑过了,现在我们应该可以正确使用manifest了,现在来讨论一个问题,什么样的页面适合使用manifest呢。关于这点,目前我们还没有具体的数据证明,但是通过manifest离线的页面,第二次访问时启动速度快了很多,而且,如果处理得当,还是有一些收益的,每次更新manifest文件以后,manifest中未修改的文件是不会被重新下载的,会返回304,而且页面中的其他静态文件,如css和img等,也能享受到传统缓存的方式。
如果你的应用是一个html5的游戏、或者是一个html的app应用,明显,采用manifest会收到很好的效果,第二次及以后加载速度都非常快,而且你的应用如果不依赖网络的话,就算用户断网了,也可以正常使用,如html5游戏,你完全可以离线来带来更好的用户体验。然而对于一些传统的站点,也想运用一下manifest新特性,如果你的站点每天都有上线更新,每天都有上线,从manifest的机制上来说,这个是不怎么适合用manifest离线的,静态资源本来就可以自己缓存,引入manifest还会带来一些维护成本已经上面提到的一些问题。但是你的站点开发完成以后,更新频率比较低,做完一版以后很长时间内不做升级(这点类似客户端),那么,你的站点就很适合用manifest离线来优化用户体验,manifest虽然带来了一些好处,但是也有很多问题。
另外,在使用过程中,某些情况下,会出现浏览器无法更新manifest的情况:目前chrome 23.0.1271.97已经找到稳定复现方法。其中:
1.问题:chrome会无法更新静态文件(这些文件包括离线主页,静态文件。)
2.原因:bug情况下,修改了manifest文件以后,通过抓包,发现某些静态文件不会发生校验。Manifest的机制是如果manifest文件发生过修改,是会校验资源列表中的静态文件的,如果文件发生过修改则会重新download这个文件,如果资源没有发生修改,服务器会返回304 。但是实际情况是,浏览器不会校验一些文件了。导致文件无法更新。此时,通过chrome://appcache-internals/方式找到浏览器的manifest缓存,然后删除,然后直接访问无法校验的静态文件。发现仍然可以访问,并且是未修改过的。后来发现是浏览器传统缓存缓存了这个文件。通过chrome://cache/可以查看到缓存的文件并没有发生修改,造成无法更新。
3.解决方法:
1.把manifest离线资源与主文件跨域存放,但这个也会导致一个问题,就是会导致dns解析变多。
2.在将manifest的列表中的静态文件的文件头中加上no-store(加no-cache不行)。这个也会导致一个问题,就是如果一个库文件,如zepto.js在m.baidu.com/static 下,manifest用到了,然后其他产品线也用到了,那么其他没用manifest的产品线就享受不了传统缓存了。
3.将manifest静态资源列表中的文件加上时间戳参数,每次修改静态文件,都主动修改下manifest中静态文件的时间戳。可能有人会认为修改一次时间戳,manifest就会本地多存一次文件,其实不是的,发现列表中如果没有该文件了,浏览器会很高级,会自动删除这个文件。不好的地方可能就是上线要多改一处地方。略微增加维护成本。
另外,有同学还碰到过浏览器将manifest文件缓存的情况,后来将这个文件的过期时间设置成了1s。
一路坑踩过来,还不知道有多少,而且一些bug出现后很难复现,总之慎用吧。
正确应用manifest来优化你的站点吧。
相关推荐
Android应用程序磁盘缓存则是Android系统为了提高应用性能和用户体验而引入的一种机制,它将经常使用的数据存储在设备的本地磁盘上,下次应用需要时可以直接从缓存读取,避免了网络延迟或IO操作的开销。 Android...
2. **manifest.appcache** - 应用程序缓存文件,列出了需要离线存储的文件列表。 3. **js** 文件夹 - 可能包含JavaScript脚本,用于处理数据存储、读取和离线状态的逻辑。 4. **styles** 文件夹 - CSS样式表,可能...
PhoneGap离线缓存是移动应用开发中的一个重要概念,它主要应用于使用PhoneGap框架构建的混合应用程序。PhoneGap允许开发者使用HTML、CSS和JavaScript来创建跨平台的原生移动应用,而离线缓存功能则使得这些应用在无...
标题中的“灵活的工具通过纯JavaScript来处理客户端应用程序缓存”指的是使用JavaScript在浏览器环境中管理应用程序的缓存机制。这通常涉及到Web应用的性能优化,特别是对于离线存储或者需要减少网络请求的情况。...
1. **定义离线缓存策略**:根据应用需求,决定使用 AppCache 还是 IndexedDB,或者两者结合。编写清单文件(对于 AppCache)或设计数据库结构(对于 IndexedDB)。 2. **初始化缓存**:在用户首次访问应用时,使用 ...
这项技术主要依赖于HTML5的Application Cache(应用缓存)API,也被称为离线存储。下面将详细介绍这个技术及其工作原理,并提供相关的源码示例。 1. **离线缓存的基本概念** HTML5的离线缓存允许开发者创建一个...
无论您是否要离线缓存资产,何时启动... You Are In Control:trade_mark: 一目了然: // start to check for updates every 30sappCacheNanny . start ( )// optionally, pass intervals in msappCacheNanny . ...
ApplicationCache(简称AppCache)是HTML5提供的一种离线存储技术,它允许浏览器缓存应用的资源文件,以便在离线状态下使用。 ##### 定义manifest: - **定义方式**:通过在HTML文档头部添加`<html manifest="...
缓存能够存储网页的静态资源,如图片、CSS样式表和JavaScript文件,以提高页面加载速度,提升用户体验。然而,有时为了调试或者隐私考虑,我们需要清除这些缓存。本文将详细介绍如何使用Chrome扩展程序以及...
HTML5的应用程序缓存,也称为App Cache,是一种强大的特性,允许Web应用程序在离线状态下仍能正常运行。这个特性通过创建一个名为manifest的文件,将特定的网页资源预先下载并存储在本地,以便在没有网络连接时使用...
离线应用缓存(Application Cache),也称为AppCache,是Web应用程序的一种离线存储机制。它允许开发者通过一个名为`manifest`的特殊文件来指定一系列静态资源,浏览器会根据这个清单文件自动下载并缓存这些资源,...
离线应用是HTML5引入的一项重要特性,它允许开发者创建可以在用户离线时仍然能运行的应用程序。在本示例中,我们将探讨如何在Tomcat7服务器上部署一个基于Firefox的离线应用,并通过相关代码了解其实现原理。 首先...
本篇文章将详细探讨如何在Android中获取应用程序缓存、计算其大小以及清理缓存的方法。 首先,了解Android的缓存机制。Android提供了多种缓存机制,如内部存储缓存、外部存储缓存(SD卡)、SQLite数据库缓存等。...
AppCache定义了一个离线应用的缓存清单,使得在离线状态下可以访问指定的网页;而Service Worker则更加灵活,可以在后台运行,拦截网络请求,实现更精细的缓存控制和数据同步。 在"OfflineX5Demo"中,可能包含了...
HTML5的离线存储,也称为离线缓存或AppCache,允许网页在没有网络连接的情况下仍能运行。通过创建一个manifest文件,开发者可以指定哪些资源(如JavaScript、CSS、图像等)需要在用户首次访问网站时缓存。这样,即使...
我们将探讨如何利用AngularJS创建一个简洁的应用,该应用不仅能够利用HTML5的本地存储(Local Storage)来持久化用户数据,还能够通过应用程序缓存(Application Cache,也称为离线存储)实现离线访问。 ### ...
在安卓系统中,管理应用程序的缓存文件是优化性能和释放存储空间的重要步骤。这篇内容主要探讨了如何在Android平台上获取应用的缓存文件、计算它们的大小以及如何清除这些缓存。首先,我们来看看“JavaApk源码说明....
应用缓存是HTML5离线存储的一种方式,允许开发者将静态资源(如HTML、CSS、JavaScript文件等)缓存到用户的本地,以便在网络不可用时仍能访问应用。启用应用缓存的方法是在HTML文档的`<html>`标签中添加`manifest`...