简单介绍Service worker

service worker提出的背景

Progressive Web App, 简称 PWA,渐进式网页应用。是提升Web App的体验的一种方法,能给用户原生应用的体验,致力于用前沿的技术开发,让网页使用如同原生App般的体验的一系列方案。

那相对于本地应用,Web 页面到底缺少了什么?

首先,Web 应用缺少离线使用能力

其次,Web 应用还缺少了消息推送的能力

最后,Web 应用缺少一级入口,也就是将 Web 应用安装到桌面,不需要每次通过浏览器来打开。

针对以上 Web 缺陷,PWA 提出了两种解决方案:通过引入 Service Worker 来试着解决离线存储和消息推送的问题,通过引入 manifest.json 来解决一级入口的问题。

Service workers 本质上充当 Web 应用程序、浏览器与网络(可用时)之间的代理服务器。

在没有安装 Service Worker 之前,WebApp 都是直接通过网络模块来请求资源的。安装了 Service Worker 模块之后,WebApp 请求资源时,会先通过 Service Worker,让它判断是返回 Service Worker 缓存的资源还是重新去通过网络请求资源。一切的控制权都交由 Service Worker 来处理。

W3C组织早在2014年5月就提出过Service Worker这样的一个HTML5 API ,主要用来做持久的离线缓存。

Service worker设计思路

1.JavaScript 和页面渲染流水线的任务都是在页面主线程上执行的,如果一段 JavaScript 执行时间过久,那么就会阻塞主线程,使得渲染一帧的时间变长,从而让用户产生卡顿的感觉,这对用户来说体验是非常不好的。

为了避免 JavaScript 过多占用页面主线程时长的情况,浏览器实现了 Web Worker 的功能。Web Worker 的目的是让 JavaScript 能够运行在页面主线程之外,不过由于 Web Worker 中是没有当前页面的 DOM 环境的,所以在 Web Worker 中只能执行一些和 DOM 无关的 JavaScript 脚本,并通过 postMessage 方法将执行的结果返回给主线程。所以说在 Chrome 中, Web Worker 其实就是在渲染进程中开启的一个新线程,它的生命周期是和页面关联的。

“让其运行在主线程之外”就是 Service Worker 来自 Web Worker 的一个核心思想

2.不过 Web Worker 是临时的,每次 JavaScript 脚本执行完成之后都会退出,执行结果也不能保存下来,如果下次还有同样的操作,就还得重新来一遍。所以 Service Worker 需要在 Web Worker 的基础之上加上储存功能。

另外,由于 Service Worker 还需要会为多个页面提供服务,所以还不能把 Service Worker 和单个页面绑定起来。在目前的 Chrome 架构中,Service Worker 是运行在浏览器进程中的,因为浏览器进程生命周期是最长的,所以在浏览器的生命周期内,能够为所有的页面提供服务。

3. Web 应用的业务安全问题是不可忽视的,所以在设计 Service Worker 之初,安全问题就被提上了日程。

关于安全,其中最为核心的一条就是 HTTP。我们知道,HTTP 采用的是明文传输信息,存在被窃听、被篡改和被劫持的风险,在项目中使用 HTTP 来传输数据无疑是“裸奔”。所以在设计之初,就考虑对 Service Worker 采用 HTTPS 协议,因为采用 HTTPS 的通信数据都是经过加密的,即便拦截了数据,也无法破解数据内容,而且 HTTPS 还有校验机制,通信双方很容易知道数据是否被篡改。

所以要使站点支持 Service Worker,首先必要的一步就是要将站点升级到 HTTPS。

除了必须要使用 HTTPS,Service Worker 还需要同时支持 Web 页面默认的安全策略,诸如同源策略、内容安全策略(CSP)等

Service worker概念

Service worker是一个注册在指定源和路径下的事件驱动worker。它采用JavaScript控制关联的页面或者网站,拦截并修改访问和资源请求,细粒度地缓存资源。你可以完全控制应用在特定情形(最常见的情形是网络不可用)下的表现。

出于安全考量,service worker只能由HTTPS承载,毕竟修改网络请求的能力暴露给中间人攻击会非常危险。

在Firefox浏览器的用户隐私模式,Service Worker不可用。

service worker特性

1.不能直接访问/操作DOM

因为service worker 是一个子线程,运行在worker上下文,所以无法直接操作DOM。

2.需要时可直接唤醒,不需要时自动休眠

在它完全独立于网页的生命周期和上下文环境里,需要时可直接唤醒,不需要时自动休眠,不会随着浏览器窗口的关闭或者与它关联的站点的关闭而失效。

3.离线缓存内容开发者可控

它相当于一个可编程的网络代理,通过编程 开发者可以对网络请求、请求结果进行拦截、改写、缓存处理等。

4.一旦被安装则永远存活,除非手动卸载

5.必须在HTTPS环境下工作(本地环境localhost也被允许)

因为service worker很强大,它能让我们对请求或者是应答进行拦截,过滤甚至是改写,那我们就需要保证这些功能是可控的,不会在网络传输的过程中被恶意篡改。

6.service worke广泛的使用了promise

service worker是一个事件驱动的worker。因为通常会等待响应后继续,并根据响应返回一个成功或者失败的操作。promise非常适合这种场景。

7.有自己独立的生命周期,不和特定网页相关

8.可以使用一些离线的缓存API ---cachestorage 和 indexdb, 不能访问locallocalStorage

同步API(如XHR和localStorage)不能在service worker中使用,只能使用一些特定的API,这些api在service worker的上下文中是全局的。

service worker生命周期

注册:

使用 navigator.serviceWorker.register() 方法首次注册service worker。如果注册成功,service worker就会被下载到客户端并尝试安装或激活,这将作用于整个域内用户可访问的URL,或者其特定子集。

navigator.serviceWorker.register('static/serviceWorker.js',{scope:'/static/'})
.then(function(registrations){
	console.log('注册成功',registrations.scope);
})
.catch(function(error){
	console.log('注册失败',error);
);

注意:这里的scope作用域参数,决定service worker控制哪些网域的页面。在指定scope的时候不能“越域”,只能指定为自身所在目录或者子级目录。

实际操作过程中serviceWorker文件路径是放到了项目的根目录下,这就意味着 serviceworker 和网站是同源的,因此在项目的根目录下的所有请求都可以代理的。

生命周期:

  1. 下载

  2. 安装

  3. 激活

用户首次访问service worker控制的网站或页面时,service worker会立刻被下载。

之后,在以下情况将会触发更新:

  • 一个前往作用域内页面的导航

  • 在 service worker 上的一个事件被触发并且过去 24 小时没有被下载

无论它与现有service worker不同(字节对比),还是第一次在页面或网站遇到service worker,如果下载的文件是新的,安装就会尝试进行。

如果这是首次启用service worker,页面会首先尝试安装,安装成功后它会被激活。

如果现有service worker已启用,新版本会在后台安装,但不会被激活,这个时序称为worker in waiting。直到所有已加载的页面不再使用旧的service worker才会激活新的service worker。只要页面不再依赖旧的service worker,新的service worker会被激活(成为active worker)。

Service Worker 内部的安装过程

几个关键性事件:

oninstall 事件的处理程序执行完毕后,可以认为 service worker 安装完成了。

activate事件触发时可以清理旧缓存和旧的service worker关联的东西。一旦激活,Service Worker 就可以开始控制在其作用域内的所有页面。

Servcie worker可以通过 FetchEvent 事件去响应请求。通过使用 FetchEvent.respondWith 方法,你可以任意劫持修改对于这些请求的响应。

注意: 因为oninstall和onactivate完成前需要一些时间,service worker标准提供一个waitUntil方法,当oninstall或者onactivate触发时被调用,接受一个promise。在这个 promise被成功resolve以前,功能性事件不会分发到service worker。

事实上:注册了 Service Worker 的页面直到再次加载的时候才会被 Service Worker 进行处理。

当 Service Worker 开始进行控制,它有以下几种状态:

  • 处理来自页面的网络或者消息请求 所触发的 fetch 及 message 事件

  • 中止以节约内存

初次安装和更新的生命周期

更新时,页面还被旧的service worker控制

Cache 和 CacheStorage

cache

表示用于Request/Response对象对的存储,作为ServiceWorker生命周期的一部分被缓存。

请注意,Cache 接口像 workers 一样,是暴露在 window 作用域下的。尽管它被定义在 service worker 的标准中,  但是它不必一定要配合 service worker 使用。

一个域可以有多个命名 Cache 对象。

除非明确地更新缓存,否则缓存将不会被更新;除非删除,否则缓存数据不会过期。

需要定期地清理缓存条目,因为每个浏览器都硬性限制了一个域下缓存数据的大小。

缓存配额使用估算值,可以使用 StorageEstimate API 获得。

CacheStorage 

表示cache对象的存储。提供一个所有命名缓存的主目录,ServiceWorker可以访问并维护名字字符串到cache对象的映射。
其它类型worker或者 window范围内也可以访问到的。

如何在浏览器中调试

  • 在 chrome 中,我们可以通过 chrome://serviceworker-internals/ 查看浏览器注册的所有 ServiceWorker;

  • Disable cache 不会影响service worker 的缓存;

  • 强制刷新会跳过service worker 的控制,直接走网络请求;

  • offLine 可以模拟离线;

  • Update on reload 会重新提取service worker,即使字节完全相同,也将其作为新版本安装,这表示将运行install事件并更新缓存。还会跳过等待阶段,以激活service worker ;

  • Bypass for network会跳过service worker 的控制,直接走网络请求;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值