什么是离线缓存
离线缓存通俗地讲,就是把资源缓存下来,即使后面没有网处于离线状态也可以访问应用。 主要用到的技术就是web应用程序清单(Web App Manifest)或者使用Service Workers方案。下面这两种方式都会介绍。
Web 应用程序清单是被称为渐进式 Web 应用程序 (PWA)的 Web 技术集合的一部分,它们是可以安装到设备的主屏幕的网络应用程序,而不需要用户通过应用商店,伴随着其他功能,比如离线可用和接收推送通知。
Service workers 本质上充当 Web 应用程序、浏览器与网络(可用时)之间的代理服务器。这个 API 旨在创建有效的离线体验,它会拦截网络请求并根据网络是否可用来采取适当的动作、更新来自服务器的的资源。它还提供入口以推送通知和访问后台同步 API。
想要了解Service workers更多的知识,可以查阅我的另一篇博客《web worker与service worker详解》。
离线缓存有什么特点
优点
1. 离线浏览:故名思义,没有网络也可以浏览网页
2. 速度快: 资源已经缓存,加载更快
3. 减少服务器负载: 浏览器只需要从服务器下载更新过或更改过的资源,不需要重新下载所有资源
缺点
离线缓存的原理
web应用程序清单(Web App Manifest)的原理
基于缓存清单文件(manifest文件)的缓存机制,这个文件是以.appcache为后缀名的,通过这个文件上的清单来解析离线缓存资源,这些资源就会像cookie一样被存储下来,之后即使没有网络,浏览器也会将这些缓存过的资源加载出来。
Service Workers的原理
Service worker 是一个注册在指定源和路径下的事件驱动worker。它采用 JavaScript 控制关联的页面或者网站,拦截并修改访问和资源请求,细粒度地缓存资源。正是基于这个可以实现离线缓存。通俗地理解就是Service Workers在离线环境下可以拦截请求, 然后加载缓存中的页面。
离线缓存的用法
manifest文件
-
部署一个manifest 在html中设置manifest属性,引用manifest文件,这一步是将清单和网页连接起来。
<!DOCTYPE html> <!-- 关联清单 --> <html lang="en" manifest="testManifest.appcache"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>h5离线缓存</title> </head> <body> <img src="./numberOne.png" height="29" width="23" alt="" /> </body> </html> -
配置manifest
CACHE MANIFEST #version 1.0 CACHE: img.jpg NETWORK: * FALLBACK: /demo/ /404.html以上代码可以分为五个部分
- CACHE MANIFEST: 必须要放在第一行
- 版本信息:当前清单的版本,最好定义,更新的时候只需修改版本号
- CACHE:需要缓存的文件放在下面
- NETWORK:需要总是从网络请求的放在下面,表示只有在有网络的情况下才可以浏览的文件
- FALLBACK:访问失败后重定向
-
实现离线缓存的需求 缓存状态:window.applicationCache对象是对浏览器的应用缓存的编程访问方式。它的status属性可以查看当前缓存的状态。 具体值如下: 0(UNCACHED): 未缓存 1(IDLE): 空闲(表示当前缓存为最新状态) 2(CHECKING): 检查中 3(DOWNLOADING): 下载中 4(UPDATEREADY): 更新就绪 5(IDLE): 缓存过期, 或者应用缓存的描述文件已经不存在了,页面无法再访问应用缓存
Service Worker
搭建一个静态资源服务器
- 安装 serve-favicon、nodemon、express:
npm install serve-favicon express nodemon --save-dev
serve-favicon: 请求网页的logo nodemon: 是一个使用工具,它将监视代码的更改,并且会自动的重新的启动服务器。 express: 是npm的第三方包,作用和Node.js内置的http模块类似,用来创建Web服务器。
- 在src目录下新建一个server文件夹,新建一个server.js文件 server.js
const path = require('path');
const express = require('express');
const favicon = require('serve-favicon');
const app = express();
// get请求
app.get('*', (req, res, next) => {
console.log(req.url);
next();
})
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
const options = {
setHeaders(res, filePath, stat) {
res.set({
'cache-control': 'no-cache'
})
}
};
app.use(express.static('src', options));
app.use(express.static('sw', {
maxAge: 0
}));
app.listen('9000', () => {
console.log('server start at localhost: 9000');
})
上述代码是把src目录下的静态资源缓存类型设置为协商缓存,客户端每次获取资源都会向服务器验证文件有效性来确认是否使用本地缓存。sw下面的server-worker.js则设置为永久缓存为01,也就是不缓存。客户端每次都会向服务器获取完整的资源。server-worker.js一定不能缓存。
- 在package.json中添加启动命令
"start": "nodemon server.js"
基本的离线缓存实现
- 在vue页面中注册service Worker
serviceRegister() {
const { serviceWorker } = navigator;
if (!serviceWorker) {
console.warn('your browser not support serviceWorker');
return;
}
window.addEventListener('load', async() => {
let sw = null;
const regisration = await serviceWorker.register('../../../service-worker.js');
sw = regisration.installing || regisration.waiting || regisration.active;
sw && sw.addEventListener('statechange', (e) => {
const { state } = e.target;
console.log(state);
})
})
}
首先从navigator中获取serviceWorker, 然后判断浏览器是否支持。当浏览器加载完成后调用serviceWorker.register注册service worker。
离线缓存的应用场景
- 页面资源文件过大,每次加载页面都很慢的情况
- 像游戏页面中有很多场景是不会变动的,也可以使用离线缓存来实现,不用每次进入页面都会重新请求静态资源,导致用户体验很不好。
- 现在比较流行的PWA大多数都是使用service worker来实现的。
特别说明
在现在的前端项目中,实现离线缓存的方式主要是以下几种:
- 服务器端设置http header cache时间
- 通过建立cdn将静态资源文件进行加速
- 使用HTML5的离线应用技术AppCache作为离线缓存