PWA 离线缓存
Posted petewell
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PWA 离线缓存相关的知识,希望对你有一定的参考价值。
- installability( 可安装性 ),可被添加自主屏与全屏运行。
- app shell: 第一次渲染个壳,等异步数据来了在填充。
- offline( 离线能力 ):离线和弱网环境也能秒开,server worker 给了 web 一个可以跑后台的线程,它可以搭配非常靠谱的 cache Api 做缓存、可以拦截所有 Http 请求并使用 Fetch API 进行 response ,一个非常完备哦的 proxy 就这么诞生了
- re-engageable:推送通知的能力,依赖 service Worker 与 http push,不过默认支持的可是 GCM
- 推送是指服务器向服务工作线程提供信息的操作
- 通知是指服务工作线程或网页脚本向用户信息的操作。
service Worker 有以下功能和特性
- 一个独立的 worker 线程,独立于当前网页进程,有自己独立的 worker context。
- 一旦被 install,就永远存在,除非被 uninstall
- 需要的时候可以直接唤醒,不需要的时候自动睡眠(有效利用资源,此处有坑)
- 可编程拦截代理请求和返回,缓存文件,缓存的文件可以被网页进程取到(包括网络离线状态)
- 离线内容开发者可控
- 能向客户端推送消息
- 不能直接操作 DOM
- 出于安全的考虑,必须在 HTTPS 环境下才能工作
- 异步实现,内部大都是通过 Promise 实现
service Worker 前提条件
- 要求 HTTPS 的环境
- 缓存机制是依赖 cache API 实现的 (cacheStorage)
- 依赖 html5 fetchAPI
- 依赖 Promise
注册
1 | if ('serviceWorker' in navigator) |
现在 Service Worker 已经被注册好了,接下来是在 Service Worker 生命周期中触发实现对应的事件处理程序了。
事件处理程序
生命周期:installing installed activating activated,这个状态变化的过程就是service worker生命周期的反应。
安装
install事件我们会绑定在service worker 文件中,在service worker 安装成功后,install事件被触发。install事件一般是被用来填充你的浏览器的离线缓存能力。为了达到这个目的,我们使用了service worker 新的标志性的存储cache API ——一个service worker上的全局对象,它使我们可以存储网络响应发来的资源,并且根据他们的请求来生成key。这个 API 和浏览器的标准的缓存工作原理很相似,但是是只对应你的站点的域的。它会一直持久存在,直到你告诉它不再存储,你拥有全部的控制权。
由于service worker是走的另外的线程,因此,window 和 DOM 都是不能访问的,因此我们要使用self访问全局上下文。
1 | const CACHE_NAME = 'yu'; |
这里我们新增了install
事件监听器,接着在事件上接了一个ExtendableEvent.waitUntil()
方法
这会确保service worker
不会在waitUntil()
里面的代码执行完毕之前安装完成
我们使用caches.open()
方法创建了一个yu的新缓存,将会是我们站点资源的缓存的第一个版本。它返回了一个创建缓存的promise
,
当它resolved
的时候,我们接着会调用在创建的缓存上的一个方法addALL()
,这个方法的参数是一个由一组相对于origin的URL组成的数组,
这个数组就是你想缓存的资源的列表caches
是一个全局的CacheStorage
对象,允许在浏览器中管理你的缓存。调用open
方法来检索具体我们想要使用的Cache
对象。
自定义请求响应
1 | self.addEventListener('fetch', function (e) |
每次任何被service worker
控制的资源被请求到时,都会触发fetch
事件,这些资源包括了指定的scope
内的html
文档,和这些html
文档内引用的其他任何资源(比如index.html
发起了一个跨域的请求来嵌入一张图片,这个也会通过service worker
。
我们可以在install
的时候进行静态资源缓存。也可以通过fetch
事件回调来代理页面请求从而实现动态资源缓存:
on install
的优点是第二次访问就可以离线访问,缺点是需要缓存的URL在编译时插入到脚本中,增加代码量和降低可维护性。on fetch
的优点是无需变更编译过程,也不会产生额外的流量,缺点是需要多一次访问才能离线访问。request
属性包含在FetchEvent
对象里,它用于查找匹配请求的缓存。cache.match
将尝试找到一个与指定请求匹配的缓存响应。如果没有找到对应的缓存,则promise
会返回一个undefined值。在这里我们通过判断这个值来决定是否返回这个值,还是调用fetch
发出一个网络请求并返回一个promise
。e.resondWith
是一个fetchevent对象中的特殊方法,用于将请求的响应发送回浏览器(提供对应的请求)。打开缓存找到匹配的响应,如果它不存在,就发情网络请求。
Fetch事件
fetch
事件是在每次网页发出请求的时候触发的,触发该事件的时候 service worker
能够拦截请求,弄决定是返回缓存的数据,还是返回真是请求响应的数据。与请求匹配的任何缓存数据都将优先被返回,而不需要发送网络请求。只有当没有现有的缓存数据时才会发出网络请求。
Service Worker 生命周期 (也许翻译的不好,尽量去看原文)
- installing: 这一阶段标志着开始注册。它想要允许设置worker-specific 的资源,例如离线模式的caches.
- 用 event.waitUntil() 通过一个promise 去延长安装service worker阶段直到e.waitUntil()里的代码执行完毕。如果所有资源安装成功缓存则安装成功,否则安装失败,则无法激活service worker。
- 用 self.skipWaiting() self 是当前context 的 global 变量。强制当前处于waiting 状态的脚本进入activate状态。
- installed:service worker 已经完成了它的安装,在等待其他service Workers 线程被关闭。
- activating: 这时没有被其他workers 控制的客户端。这个阶段允许workers 去完成安装并且清理其他 worker以及关联缓存的就缓存资源,等待新的service worker线程被激活。
- activated:现在可以处理方法事件。
- message: service worker 运行于独立context 中,无法直接访问当前页面主线程的DOM信息,但是通过postMessageAPI ,可以实现他们之间的消息传递,这样主线程就可以接受service worker 的指令操作DOM。
manifest.json
pwa 添加至桌面的功能实现依赖于manifest.json。
基本功能
- name:string 应用名称,用于安装横幅、启动画面显示
- short_name:string 应用短名称,用于主屏幕显示
- icon:img 应用图标列表,其中包括:
- src:string 图标URL
- type:图标的mime 类型
- size:图标尺寸。当PWA添加到主屏幕时,浏览器会根据有效图标的size 字段进行选择,如果匹配到的图标路径错误,将会显示浏览器默认icon。
- start_url:string= 应用启动地址
- background_color:color css色值
- display: string 显示类型
- fullScreen: 应用的显示界面将占满整个屏幕
- standalone: 浏览器相关UI(导航栏、工具栏等)将会被隐藏
- minimal-ui: 显示形式与standalone类似,浏览器相关UI会最小化为一个按钮,不同浏览器在实现上略有不同
- browser: 浏览器模式,与普通网页在浏览器中打开的显示一致
- orientation: string 应用显示方向
- theme_color: 主题颜色
设置作用域
- 如果没有在manifest中设置scope,则默认的作用域为manifest.json所在的文件夹;
- start_url 必须在作用域范围之内;
- 如果start_url 为相对地址,其根路径收scope所影响;
- 如果start_url 为绝对地址(以/开头),则该地址将永远以/作为跟地址;
添加启动动画
当PWA添加到主屏幕点击打开时,幕后执行了若干操作:
- 启动浏览器
- 启动显示页面的渲染器
- 加载资源
在这个过程中,由于页面未加载完毕,因此屏幕将显示空白并且看似停滞。如果是从网络加载的页面资源,白屏过程将会变得更加明显。因此 PWA 提供了启动画面功能,用标题、颜色和图像组成的画面来替代白屏,提升用户体验。
目前,如果修改了manifest.json 的应用的名称,已经添加到主屏幕的名称并不会改变,只有当用户重新添加到桌面时,更改后的名称才会显示出来。但是未来版本的chrome 支持自动更新。
以上是关于PWA 离线缓存的主要内容,如果未能解决你的问题,请参考以下文章
前端性能优化之----静态文件客户端离线缓存_20191110
前端性能优化之----静态文件客户端离线缓存_20191110