Web App 开发之 HTML5 离线缓存
白羽 2018-06-19 来源 :网络 阅读 836 评论 0

摘要:本文将带你了解 Web App 开发之 HTML5 离线缓存,希望本文对大家学WEBAPP有所帮助。



一. 离线网络应用程序基础

离线网络应用程序的核心是一个 content type (内容类型) 为 cache-manifest 的文本文件。这个文件保存了应用程序中需要离线存储的文件(HTML, CSS, JavaScript, 图片等)。举一个简单的例子,若一个应用程序由以下文件组成:

· index.html

· demo.css

· demo.js

· logo.png

index.html 为主页,其他文件是主页中引用的资源,如果我们需要离线缓存这个应用程序,需要在 index.html 的同级目录下增加一个 manifest 文件,并命名为 .manifest 后缀文件,而文件中的内容可以这样编写:


   

CACHE MANIFEST

./index.html

./demo.css

./demo.js

./logo.png

   

可以看出,以上文件的路径是相对路径,这里是相对于 manifest 文件而言的。当然,你也可以使用绝对路径,这并不影响 manifest 的使用。

manifest 文件的编写很简单,但启用离线缓存还需一些步骤。首先是需要把 manifest 文件和应用程序关联起来,即把页面指向缓存名单,方法是为 html 标签指定 manifest 值,例如:

1

   

<html manifest="demo.manifest">

   

其中 demo.manifest 是例子中编写的 manifest 列表文件。

小提示:若应用程序中有多个页面,则每个页面都需要与 manifest 关联起来。

接着,开发者必须给 manifest 文件指定 text/cache-manifest 内容类型,这样浏览器才能识别它。关于具体的方法,如果你的服务器支持 .htaccess ,可以在 .htaccess 中写入以下语句:

1

   

AddType text/cache-manifest .manifest

   

这样做可以把 text/cache-manifest 的 MIME 类型和 .manifest 文件关联起来。当然,可能开发者并没有 .htaccess 的编写权限,但实际上,开发者可以使用另外一些更实用的方法达到目的。因为在实际的项目开发中,应用程序中的文件数量不会只像上例中仅有的 4 个,如果有很多的文件需要缓存,每个文件都需要手动写入 manifest 文件实在比较费时,更麻烦的是,每次改动这些文件都必须相应地改动 manifest 文件,因此 更加建议开发者使用后台脚本直接获取需要缓存的文件并写入一个 manifest 列表,熟悉的后台脚本是 PHP ,在 PHP 中,可以直接在代码中设置 MIME 类型,这样就不需要配置 Web 服务来完成对 manifest 的支持了。至于具体如何使用 PHP 编写 manifest ,会在下面详细介绍。

二. 浏览器支持

关于离线网络应用程序在现代浏览器中都已经实现完整的支持,IE 则完全不支持。具体如下:

Chrome 4+ , Firefox 3.5+ , Safari 4+ 和 Opera 10.6+

三. 白名单

默认情况下,开发者会为应用程序中所有文件指定缓存,但实际上,仍有一些资源可能需要强制取消缓存,即必须访问网络资源,离线时该资源不可用。为元素强制取消缓存可以在 manifest 文件中使用关键字 NETWORK: 。在 NETWORK: 关键字下添加文件的列表,这些文件会强制取消缓存,而这个文件列表就称为白名单 (Whitelist) 。实际上,对于需要缓存的资源也是有关键字的,这个关键字是 EXPLICIT: ,但所有资源列表的开头如果没有添加关键字,默认都会被认为在 EXPLICIT: 关键字的列表下,因此需要缓存的资源列表开头可以忽略不写关键字(如上例)。

例如,对上例进行扩展,把 logo.png 添加到白名单,可以这样编写 manifest 文件。


   

CACHE MANIFEST

./index.html

./demo.css

./demo.js

 

NETWORK:

./logo.png

   

四. 备选名单

备选名单是对于白名单的补充,在白名单中,没有联网时,资源不能加载,这样会导致页面出现错误,如上例中,"logo.png" 被设置为白名单,如果用户离线浏览该应用程序,会出现一个损坏的图片链接,为了避免这种情况,可以使用 FALLBACK: 指定一个备选名单,备选名单中需要为一个资源准备两个文件,若能正常联网,会引用第一个文件,离线时则引用第二个文件,关于这个特点,有一个很实用的应用 —— 表明程序是离线工作还是联网工作,在不同的状态下引用不同的图片即可方便地表明状态。接下来 继续扩展上例,为 logo.png 指定一个离线时的替换图片 backup.png 。


   

CACHE MANIFEST

./index.html

./demo.css

./demo.js

 

FALLBACK:

./logo.png ./backup.png

   

五. 更新 manifest

似乎,经过上面三个步骤后,应用程序的离线缓存已经很好的工作了。但有一个很重要的问题仍需注意 —— 根据离线缓存的工作原理,当用户第一次使用应用程序时,浏览器会根据 manifest 文件里的列表下载指定的资源,在下次使用该应用程序时,浏览器会自动加载这些资源的副本,那么假如开发者修改了程序,浏览器仍旧会加载本地的资源,因此我们需要给浏览器一个提示,程序已经更新。

那么什么时候浏览器会更新本地缓存呢?

只有当 manifest 修改后浏览器才会重新下载 manifest 中所有指定需要离线缓存的文件。而检测 manifest 是否修改过是对 manifest 文件的内容逐个字符进行比较,包括注释和空行。当然,大多情况下,修改程序时并不会影响主要的文件,所以 manifest 中的文件列表也不会有改动,因此需要改动 manifest 以通知浏览器程序已更新的最好办法是修改注释,开发者可以在 manifest 文件中添加一行注释,比如说是程序的版本号,当程序更新后同时修改 manifest 文件中这个版本号,浏览器就会判定程序已经更新,自动重新下载所有需要离线缓存的资源。例如,把上例改成:


   

CACHE MANIFEST

# version 1.0

./index.html

./demo.css

./demo.js

 

FALLBACK:

./logo.png ./backup.png

   

需要注意的是,"CACHE MANIFEST"是必要行,并且必须在 manifest 文件中的第一行。这样下次更改程序后同时修改 manifest 的程序版本号,浏览器就可以判定程序更新了。

手动更新缓存

当然,为了能更精确地控制程序更新,最好是使用手动方法更新缓存,离线网络应用程序规范中也提供了相应的手动更新缓存的方法。开发者可以使用 window.applicationCache.update() 方法手动更新缓存,为了更准确地判断是否需要更新,开发者可以先检测 window.applicationCache.status 的值,若其值为 "UPDATEREADY" (即浏览器检测到 manifest 已被修改), 可以调用 window.applicationCache.update() 方法更新缓存。例如:


   

if ( window.applicationCache.status == window.applicationCache.UPDATEREADY ){

    window.applicationCache.update();

}

   

六. 使用 PHP 脚本编写 manifest 文件

如上面所说,使用脚本编写 manifest 文件可以同时解决 manifest 文件扩展名与 MIME 类型关联起来,还可以自动列出缓存文件。具体的编写如下:


header('Content-Type: text/cache-manifest');

echo "CACHE MANIFEST\n";

 

$allHashes = ""; // 创建一个字符串保存文件的 md5 值

 

$dir = new RecursiveDirectoryIterator(".");

foreach(new RecursiveIteratorIterator($dir) as $file){ // 获取当前目录并遍历文件

    if( $file->IsFile() && // 判断获取内容为文件

        $file->getFilename() != "manifest.php" && // "manifest.php" 不缓存

        $file->getFilename() != "logo.png" && // 备选资源不缓存

        $file->getFilename() != "offline.png" &&

        !strpos( $file, '/.' ) &&

        substr( $file->getFilename(), 0, 1 ) != "."){

 

        echo "./" . $file->getFilename() . "\n";

        $allHashes .= md5_file($file); // 把每一个缓存的文件的 md5 值连接起来

    }

  

}

  

echo "FALLBACK:\n"; // 输出备选名单

echo "./logo.png ./offline.png\n";

 

echo "# " . md5($allHases) ."\n"; // 把连接起来的 md5 值重新计算一个 md5(因为连接所得的字符串过于冗长)

   

在这个脚本中,获取了应用程序的目录并把目录中的文件逐个添加到缓存列表,同时在这个过程中排除如 "manifest.php" 和备选资源等文件,并且,对每一个缓存的文件计算 md5 值,把这些值连接起来后重新计算一个 md5 并输出到一行注释中,这样缓存的文件只要有一个发生了改变,都会影响这行注释,从而使到整个 manifest 文件发生改变,这样就并不需要在更新程序后手动修改 manifest 文件。可以看出,如果需要缓存的文件很多时,该方法将会十分方便,并且更新程序后 manifest 文件也会被自动修改。当然,这只是使用脚本编写 manifest 的其中一种方式,开发者应视具体情况而制定相应的脚本。

七. 关于离线网络应用程序的属性、方法和事件

在 “手动更新缓存” 中,提到了一个对象 window.applicationCache ,这个对象中包含了与离线网络应用程序相关的属性、方法和事件,除了上面涉及到的 status 属性和 update() 方法外,还有其他的相关内容,下面开始对它们进行详细介绍。

1. 属性

window.applicationCache 对象中具有一个属性 status ,该状态会根据当前的缓存状态显示不同的值和状态编号,具体的属性值如下:

· UNCACHED 未开始缓存状态。 状态编号:0

· IDLE 空闭状态。 状态编号:1

· CHECKING 正在检查 manifest 文件是否存在。 状态编号:2

· DOWNLOADING 正在下载缓存文件。 状态编号:3

· UPDATEREADY 更新下载已完成,等待更新状态。 状态编号:4

· OBSOLETE 废弃状态。 状态编号:5

2. 方法

接着,是相关的方法,具体如下:

· update() 检测与文档关联的 manifest 文件是否有修改,如果有修改,则更新缓存。若 manifest 文件不存在或该缓存已废弃,则会抛出一个 InvalidStateError 错误。

· abort() user agent 会发出一个信号给当前的缓存对象,中止应用缓存的下载,如果页面没有使用离线网络应用程序,那么在尝试发出信号后该方法不会再执行任何操作。

· swapCache() 手动执行本地缓存更新,并且只能在 updataReady 事件触发时在事件回调函数中调用。但需要注意该方法不会立即更新缓存文件,仍需要刷新页面才生效。若文档关联的 manifest 文档不存在,会抛出一个 InvalidStateError 错误。

3. 事件

除了属性和方法,window.applicationCache 对象还会根据一些情况在其身上触发一些事件,开发者应该了解这些事件,根据所触发的事件,可以了解一个正在运作的离线缓存的工作情况,然后根据不同的情况作出适当的处理。

· checking 浏览器在检测到 html 标签上有 manifest 属性后,会检查相关联的 manifest 文件是否存在,同时触发 checking 事件。

· noupdate 在检测到 manifest 没有更新(即没有修改)时触发。

· downloading 缓存下载时触发。

· progress 下载进度(阶段性事件)。

· cached 已根据 manifest 文件中指定的要求下载相应的资源。

· updateready 更新时,已根据 manifest 文件中指定的要求重新下载相应的资源。

· obsolete manifest 文件请求发生 404 或 410 错误时触发,发生此事件表明该缓存已被删除。

· error 以下四种情况都会触发 error 事件:1. manifest 文件请求发生 404 或 410 错误; 2. manifest 文件没有修改,但页面无法正确引用 manifest ;3. 根据 manifest 文件更新资源时发生致命错误(如上面提到的 InvalidStateError 错误);4. 当资源正在更新时 manifest 文件被修改。

这里 需要指出一点,以上这些事件并不会在一个缓存过程中全部触发,如 error(前三种情况) , updateready , obsolete , noupdate , cached 均为一个缓存过程中的最终事件,在一次缓存过程中只会出现其中一个。又如 cached 事件,必须要有下载资源并且在完成后才触发,即第二次打开页面并且 manifest 没有修改是不会触发 cached 事件(没有下载资源),开发者应仔细注意每个事件的触发时刻,判断在不同情况下应该利用何种事件。

这个例举一个例子,使用 addEventListener 监听 cached 事件,检测到 cached 事件发生时弹出提示,即代表离线资源已经下载完成。


   

if(window.applicationCache) {

 

    window.applicationCache.addEventListener('cached', function(){

        alert('cached');

    }, true);

 

}

   

八. 完整实例 Demo

为了使读者更好的理解离线网络应用程序的具体使用,这里会把上面逐步扩展的例子写成完整 Demo (为了简化例子结构,这里只使用 addEventListener 监听事件,请使用 Chrome, Firefox 等现代浏览器浏览 Demo )。


 


本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之WebApp频道!


本文由 @白羽 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程