基于Service Worker的离线应用构建

1. Service Worker 简介

Service Worker是什么

service worker 是独立于当前页面的一段运行在浏览器后台进程里的脚本,它是一个独特的Web Worker。

平常浏览器窗口中跑的页面运行的是主JavaScript线程,DOM和window全局变量都是可以访问的。Service Worker是走的另外的线程,可以理解为在浏览器背后默默运行的一个线程,或者说是独立于当前页面的一段运行在浏览器后台进程里的脚本。它脱离浏览器窗体,异步地运行在一个完全独立的上下文环境,不会对主线程造成阻塞。在service worker中,window以及DOM都是不能访问的,但可以使用PostMessage跟主进程进行通信。

Service Worker的作用

1.离线缓存(重点)依赖于cacheAPI

2.消息推送(重点)依赖于Google的推送服务,国内使用意义不大

3.后台数据同步

4.响应来自其它源的资源请求

5.集中接收计算成本高的数据更新,比如地理位置和陀螺仪信息,这样多个页面就可以利用同一组数据

6.在客户端进行CoffeeScript,LESS,CJS/AMD等模块编译和依赖管理(用于开发目的,一些在线编译网站)

7.后台服务钩子(基于推送)

8.自定义模板用于特定URL模式

9.性能增强,比如预取用户可能需要的资源,比如相册中的后面数张图片

Service Worker的局限性

1.浏览器兼容性:不支持IE,但是由于是另外一个线程,不影响在IE上使用。

使用ServiceWorker cache polyfill让旧版本浏览器支持 ServiceWorker cache API。

[浏览器兼容性](ww1.sinaimg.cn/large/007iU…)

2.https: Service Worker必须是https协议的,但本地环境下http://localhost或者http://127.0.0.1也可以的。

通过service worker可以劫持连接,伪造和过滤响应,为了避免这些问题,只能在HTTPS的网页上注册service workers,防止加载service worker的时候不被坏人篡改。

Github Pages是HTTPS的,可以通过Github做一些尝试

3.service worker运行在它们自己的完全独立异步的全局上下文中,也就是说它们有自己的容器。

4.service worker没有直接操作DOM的权限,但是可以通过postMessage方法来与Web页面通信,让页面操作DOM。

5.service worker是一个可编程的网络代理,允许开发者控制页面上处理的网络请求。

6.浏览器可能随时回收service worker,在不被使用的时候,它会自己终止,而当它再次被用到的时候,会被重新激活。

7.service worker的生命周期是由事件驱动的而不是通过Client。

2. Service Worker的基本概念

Service Worker生命周期

service worker拥有一个完全独立于Web页面的生命周期

Service Worker生命周期的反应:installing → installed → activating → activated 'install'用来缓存文件,'activate'用来缓存更新

[Service Worker生命周期](pic.superbed.cn/item/5c8b19…)

注册service worker,在网页上生效

安装成功,激活 或者 安装失败(下次加载会尝试重新安装)

激活后,在sw的作用域下作用所有的页面,首次控制sw不会生效,下次加载页面才会生效

sw作用页面后,处理fetch(网络请求)和message(页面消息)事件 或者 被终止(节省内存)。

service worker的调试

1、chrome://serviceworker-internals

[serviceworker-internals](ww1.sinaimg.cn/large/007i4…)

2、网页中Application

[Application1](ww1.sinaimg.cn/large/007iU…)

[Application2](ww1.sinaimg.cn/large/007i4…)

Service Worker的用法

HTML 里面:

引进sw-demo-cache.js

webapck中的使用:

获取文件目录 引入第三个模块glob,递归获取打包后的文件目录。导出目录 通过webpack的DefinePlugin插件,导出上步获取的目录

web和service worker的通信 通过postMessage实现web和service worker间的通信

Service Worker的业界生态

Service Worker 主要在PWA中担任离线缓存应用技术的角色。

Webpack的offline-plugin, offline-plugin 可以把我们的多页面应用进行缓存,即使这些html文件时独立的。它作为一个webpack插件使用,为我们自动生成sw.js文件。

workbox:是sw-precache和sw-toolbox的继任者。它是一组内容库和工具,用于生成 Service Worker、预缓存、路由以及运行时缓存。另外,Workbox还附带模块,可轻松地将后台同步和Google analytics集成到 Service Worker。通俗来看,它能帮助开发人员降低Service Worker的使用成本,但目前没办法高效解决大型站点多团队多应用协作的问题。主要用于SPA。主要应用有淘宝最近分享的workbox3.0

lavas:是一套基于 Vue 的 PWA 解决方案,能够帮助开发者快速搭建 PWA 应用,解决接入 PWA 的各种问题,简单来看lavas = vue + pwa。它适用于新应用的开发,对于老应用使用PWA有一定成本,而且同样目前也没办法高效解决大型站点多团队多应用协作的问题。主要用于SPA。

点评PWA平台

开发人员接入只需两步:

在PWA管理平台填写相关配置,这些配置会存到redis集群。

在页面引入一小段js代码,这段代码在页面加载时执行,先向配置平台发出sw-reg.js请求,拉取配置,然后在页面注册sw。

为了提高sw可用性,管理平台设计时将sw与配置解耦。实际页面在零基础情况下应用PWA时会经历三次页面请求才能成功使用:

第一次页面请求注册sw并控制页面;

第二次页面请求拉取配置通过postmessage形式传给sw并存储在IndexedDB;

第三次页面请求时sw会拦截页面上所有http请求,根据配置执行相应的处理策略。

从框图中可以看到,sw将缓存存储在CacheStorage,数据和配置存储在IndexedDB。整个流程包括服务端和客户端都有报警监控,错误上报到cat。

整个平台设计与业务基本完全解耦,要求业务在不接入PWA情况下也能正常使用,平台只是帮助业务在页面请求加载各个环节增强体验。

Service Worker 的应用

应用场景很广泛,一些应用到sw的站点:

百度、谷歌、腾讯、163网易、微博(m.weibo.cn/)、淘宝 PC 首页......

基本应用场景在手机端使用比较多,Web端也很多。

手机端应用得比较好的是mobile.twitter.com,在手机上的体验跟原生很接近。

Service Worker在我们的项目中的应用:

我们的设想是在离线的情况下,用户能够无感知的进行操作,并且在操作之后能把

操作对应的上传到服务器上……

为了达成这个目标,我们需要使用SW在浏览器中做好缓存策略的选择:

Service Worker 的策略机制:

1 不影响安装的资源预缓存 offline-page-not-dependent-on-install

对于某些固定不变的静态资源,我们习惯在Service Worker初次安装的install事件中将其缓存,但资源过大或者网络不佳都会造成资源并未全部下载成功而导致Service Worker安装被中断,只有等下次用户在打开相应页面。这里可以将静态资源按优先级分为两类,一类是重要资源,一类是非重要资源,将重要资源放到安装等待队列中,非重要资源放到独立的队列中,这样只需要重要资源全部都加载成功就可以成功安装Service Worker了,可以提高Service Worker安装成功率。

2 渐进式缓存 progressive-cache

对于在install中发现没有缓存,页面又依赖但又不经常变化的资源,可以在页面打开或发生用户交互时触发fetch然后使用fetch api再去网络拉取,将返回正常的response缓存起来以便下次使用。

3 仅使用缓存 cache-only

在fetch事件中,仅去匹配资源,若匹配失败,表现出来的就是前端页面对于该 资源加载失败。这里容错性比较差,适合页面资源都是静态资源的,且不能使用不影响安装的资源预缓存。

4 仅使用网络 network-only

在fetch事件中,仅将request重新抽出用fetch去网络加载并返回给前端页面。适用于资源大多是动态资源、实时性要求高的场景。

5 缓存优先 offline-page

简单的资源缓存中使用的就是缓存优先策略,先去缓存匹配,匹配失败折回网络,这算是最常用、容错性能好的一种策略。

6 网络优先 network-first

在fetch事件中先去网络fetch,当出现服务器故障或者网络不良时,折回本地缓存,目的是为了展示最新的数据,对实时性要求比较高但又能够带来良好体验的应用,比如天气类型应用。

7 速度优先 speed-first

在fetch事件中同时发起本地缓存匹配及网络请求,谁先返回使用谁的,该方案适用于对性能要求比较高的站点,缩短了缓存优先策略中有可能缓存中没有资源再折回网络的时间消耗。

8 Service Worker跨域资源的缓存策略 cross-resources

a. 首先保证跨域的资源来自安全的https地址;

b. 保证跨域资源服务器的response中Access-Control-Allow-Origin中包含当前的页面所在域或者为*;

c. 对于前端页面中的跨域资源的url可以附带“cors=1”参数,以便Service Worker在拦截之后可以判断出是跨域请求从而重新进行组装cors请求。

淘宝分享的WorkBox3.0实践中推荐使用的方案:

HTML,如果你想让页面离线可以访问,使用 NetworkFirst,如果不需要离线访问,使用 NetworkOnly,其他策略均不建议对 HTML 使用。

CSS 和 JS,情况比较复杂,因为一般站点的 CSS,JS 都在 CDN 上,SW 并没有办法判断从 CDN 上请求下来的资源是否正确(HTTP 200),如果缓存了失败的结果,问题就大了。这种我建议使用 Stale-While-Revalidate 策略,既保证了页面速度,即便失败,用户刷新一下就更新了。

如果你的 CSS,JS 与站点在同一个域下,并且文件名中带了 Hash 版本号,那可以直接使用 Cache First 策略。

图片建议使用 Cache First,并设置一定的失效事件,请求一次就不会再变动了。

上面这些只是普适性的策略,见仁见智。还有,要牢记,对于不在同一域下的任何资源,绝对不能使用 Cache only 和 Cache first。

实际操作DEMO:

github.com/fomenyesu/s…

THE END!

转载于:https://juejin.im/post/5c8b047cf265da2d8e712e76

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值