service worker

89 阅读5分钟

第一次知道service worker是在面试题中看到的,但是当时由于深恶痛绝八股文,只是把service worker看做一道面试题而已。想深入了解service worker的原因是小程序的框架是双线程的,那为什么小程序会比浏览器渲染网页多一个线程? 小程序的逻辑层到底是怎么实现? 于是上mdn学习一下service worker。强烈建议想学习service worker的同学们上mdn去看,真的很详细,本文也主要是摘抄mdn上的内容。

小程序开发框架的逻辑层使用 JavaScript 引擎为小程序提供开发 JavaScript 代码的运行环境以及微信小程序的特有功能。

逻辑层将数据进行处理后发送给视图层,同时接受视图层的事件反馈。

开发者写的所有代码最终将会打包成一份 JavaScript 文件,并在小程序启动的时候运行,直到小程序销毁。这一行为类似 ServiceWorker,所以逻辑层也称之为 App Service。

1. 什么是service worker

Service worker 本质上充当 Web 应用程序、浏览器与网络(可用时)之间的代理服务器。这个 API 旨在创建有效的离线体验,它会拦截网络请求并根据网络是否可用来采取适当的动作、更新来自服务器的资源。它还提供入口以推送通知和访问后台同步 API。

Service worker 运行在 worker 上下文:因此它无法访问 DOM,相对于驱动应用的主 JavaScript 线程,它运行在其他线程中,所以不会造成阻塞。

出于安全考量,Service worker 只能由 HTTPS 承载,毕竟修改网络请求的能力暴露给中间人攻击会非常危险,如果允许访问这些强大的 API,此类攻击将会变得很严重。

中间人攻击(Man-in-the-middle attack,MitM)会在消息发出方和接收方之间拦截双方通讯。举例来说,Wi-Fi 路由器就可以被破解用来进行中间人攻击。

2. service worker能干什么

  • 后台数据同步

  • 响应来自其他源的资源请求

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

  • 在客户端进行 CoffeeScript、LESS、CJS/AMD 等模块编译和依赖管理(用于开发目的)

  • 后台服务钩子

  • 自定义模板用于特定 URL 模式

  • 性能增强,比如预取用户可能需要的资源,比如相册中的后面数张图片 未来 service worker 能够用来做更多使 web 平台接近原生应用的事。值得关注的是,其他标准也能并且将会使用 service worker,例如:

  • 后台同步:启动一个 service worker 即使没有用户访问特定站点,也可以更新缓存

  • 响应推送:启动一个 service worker 向用户发送一条信息通知新的内容可用

  • 对时间或日期作出响应

  • 进入地理围栏

我个人的话会对其实对响应推送比较感兴趣,因为之前在项目要实现服务器向前端推送消息的需求。当时并不是使用 PUSH API实现的。在此链接我的另一篇文章,介绍了一下目前能实现服务器向前端推送消息的技术方案。juejin.cn/editor/draf…

3. service worker的工作的基本过程

通常遵循以下基本步骤来使用 service worker:

  1. 获取 service worker 代码,然后使用 serviceWorkerContainer.register() 来注册。如果成功,service worker 将在 ServiceWorkerGlobalScope 中执行;这本质上是一种特殊的上下文,在主脚本执行线程之外运行,没有访问 DOM 的权限。Service Worker 现在已为处理事件做好准备。
  2. 安装完成。install 事件始终是发送给 service worker 的第一个事件(这可用于启动填充 IndexedDB 和缓存站点资源的过程)。在此步骤期间,应用程序正在为离线可用做准备。
  3. 当 install 程序处理完成时,service worker 被视为已安装。此时,service worker 的先前版本可能处于激活的状态并控制着打开的页面。由于我们不希望同一 service worker 的两个不同版本同时运行,因此新版本尚未激活。
  4. 一旦 service worker 的旧版本控制的页面都已关闭,就可以安全地停用旧版本,并且新安装的 service worker 将收到 activate 事件。activate 的主要用途是去清理 service worker 之前版本使用的资源。新的 service worker 可以调用 skipWaiting()要求立即激活,而无需要求打开的页面关闭。然后,新的 service worker 将立即收到 activate 事件,并将接管任何打开的页面。
  5. 激活后,service worker 将立即控制页面,但是只会控制那些在 register() 成功后打开的页面。换句话说,文档必须重新加载才能真正的受到控制,因为文档在有或者没有 service worker 的情况下开始存在,并在其生命周期内维护它。为了覆盖此默认行为并在页面打开的情况下,service worker 可以调用 clients.claim()方法。
  6. 每当获取新版本的 service worker 时,都会再次发生此循环,并在新版本的激活期间清理上一个版本的残留。

以下是可用的 service worker 主要监听的一些事件: