PWA系列 -- Service Workers 概述

PWA

2018-11-24

# 背景信息

1-1.png

浏览器有很多种 workers,我们先看看 Web Workers。最常见的 Web Workers 有下面两种,

  • Dedicated Worker,专用 Worker,只能被创建它的JS访问。
  • Shared Worker,共享 Worker,可以被同一域名下的JS访问。 JavaScript 是单线程的,即一个浏览器进程中只有一个 JavaScript 的执行线程,同一时刻内只会有一段代码在执行。Web Worker 的目的,就是为 JavaScript 创造多线程环境,允许主线程将一些任务分配给子线程。Web Workers 一般是用于在后台执行一些耗时较长的 JavaScript,避免影响 UI 线程的响应速度。 Dedicated Worker 或 Shared Worker 最主要的能力是,
  • 后台运行JS,不影响 UI 线程。
  • 使用消息机制实现并行,可以监听 onmessage 事件。 我们可以看到 Dedicated Worker 和 Shared Worker 专注于解决“耗时的 JS 执行影响 UI 响应”的问题。而 ServiceWorker 则是为解决"Web App 的用户体验不如 Native App”的普遍问题而提供的一系列技术集合,显然 ServiceWorker 给它自己的使命更加远大。虽然规范把它定义为 Web Workers,但它已不是一个普通的 Worker 了。

# ServiceWorker 的能力

power.jpg 规范文档提到 ServiceWorker 是一个注册在指定源和路径下的事件驱动 Worker。官方入门文档提到它能提供丰富的离线体验,周期的后台同步,消息推送通知,拦截和处理网络请求,和管理资源缓存。这些技术细节我们在后续的文章逐一进行分析,现在我们先看看这些能力的意义。

  1. 丰富的离线体验 很多文档都会提到,ServiceWorker 能提供丰富的离线体验,但大家可能会想,我们好像很少需要离线的业务,甚至一些高政策风险的业务,连主文档都不允许缓存,那离线是否就没有实际意义了呢? 有实际意义的离线,一般不是指断开网络能访问,而是指在用户想访问之前,能提前把资源加载回来。离线并不是一直都断开网络,而是在网络连接良好的情况下,能把需要的资源都加载回来。一些比较糟糕的做法是在 WiFi 网络下把整个 App 客户端的资源都拉下来,这样其实很多资源是用户不需要的,浪费了用户的网络和存储。ServiceWorker 提供了更好更丰富的离线技术,Push + Fetch + Cache 这些技术结合能够提供非常完美的离线体验。比如,在某应用的小程序页面发版时,推送消息给应用客户端,客户端唤起页面的 ServiceWorker,去将需要用到的资源提前 Fetch 回来。
  2. 消息推送通知 ServiceWorker 的消息推送,其实是提供了一种服务器与页面交互的技术。消息推送,在 Native 或 Hybird App 已经比较常见。很多 Hybird App 里面其实还会有一些 Web 页面,在没有 ServiceWorker 消息推送之前,消息是推送不到页面的。消息能推送到页面,意味着页面提前知道要发生的一些事情,能提前把这些事情做好。
  3. 管理资源缓存 Web标准中提供了很多存储相关的 H5 API,比如,Application Cache,Local Storage等。但这些 API 都不是非常好用,主要原因在于给予页端的控制权太少,页端还是不能完全控制每一个资源请求的存储,或多或少会有一些趟不过的坑。ServiceWorker Cache API 的出现彻底改变了这一局面,让页面可以方便的操作每一个资源的存储。
  4. 拦截资源请求 一般来说,基于 Webview 的客户端拦截网络请求,都会基于 WebViewClient 的标准的 shouldInterceptRequest 接口。那么 ServiceWorker 的请求在 Webview 还能不能拦截呢?WebViewClient 的标准的 shouldInterceptRequest 接口无法拦截 ServiceWorker 的请求,但 Chrome 49.0 提供了新的 ServiceWorkerController 可以拦截所有 ServiceWorker 的请求。另外,页端可以监听 Fetch 事件,通过 FetchEvent.respondWith 返回符合期望的 Response,即页端也能拦截 Response。
  5. 发起资源请求 在 ServiceWorker 之前,页面一般通过 XMLHttpRequest 发起资源请求,但 XHR 有一定的局限性,比如,它不像普通请求那样支持 Request 和 Response 对象,也不支持 Streaming Response,一些跨域的场景也限制较多。而这些恰好是 ServiceWorker 的能力所在,Fetch API 支持 Request 和 Response 对象,也支持 Streaming Response,Foreign Fetch 还具备跨域的能力。 看了上面的能力,是不是觉得和 Native Apps 的能力很像?不错,ServiceWorker 对标的就是Native App,它的能力还在不断的扩展中,比如,Navigation Preload。

# ServiceWorker 的意义

Progressive Web Apps,一种能给 Web 带来令人惊叹的用户体验的新方式。里面提到三种最核心的用户体验。

  1. Reliable:即使在不确定的场景下(比如,网络不稳定,用户停留时间不确定),依然能提供可靠的Web服务。
  2. Fast:提供极速流畅的用户体验。
  3. Engaging:提供与 Native App 一致的用户体验。 我们看看 ServiceWorker 是否可以很好的达到上述要求?
  • Background Sync 技术在页面已被关闭,或用户已退出应用,甚至用户已重启手机,它都能保证同步请求能正确地被触发,这就是提供可靠服务的一个例子。
  • Fetch 技术和 Cache 技术能让页面完全控制资源请求和响应,提供了 HTTP Cache 层面操控缓存的能力,只要合理使用几乎能保证在页面加载之前,能把需要的资源都提前加载回来,把联网体验转换为离线体验,能极大的提升页面性能。
  • Web Push 技术让页面服务器与页面交互成为可能,与 Fetch 技术结合可以提前让页面更新资源,与 Web Notifications 结合可以在需要的时候及时通知到用户。 我们相信,在不远的将来,很可能会有更加强大的技术加入到 ServiceWorker,例如让页面操控渲染流程的技术。

# ServiceWorker 的门槛

PWA.jpg ServiceWorker 在国内的使用,有一定的门槛,

  1. 要求 HTTPS 页面 一般来说,能力越大责任越大,ServiceWorker 也不例外,它在提供了强大的能力的同时,也增加了安全风险。为了防止页面被劫持,ServiceWorker 是要求要在 HTTPS 页面下使用的。虽然 HTTPS 已是大势所趋,但对一些安全性要求不高的站点来说,成本还是挺大。
  2. Push 功能缺失 Push 的推送服务器,Chromium 默认使用 GCM/FCM,在国内都不能访问,无法使用。浏览器厂商自己搭建 Push 服务器,成本也不低,目前国内还未有浏览器厂商支持标准的 Push 服务。
  3. Background Sync 功能缺失 Chromium 默认的 Background Sync 功能,需要依赖 Google Play,同样在国内无法使用。
  4. iOS 仅支持基本功能 iOS 的 ServiceWorker 能力尚未达到 Android 的能力,今后是否能达到同等能力也是未知数。 table.png

# 总结

end.jpg 虽然 ServiceWorker 有一定的门槛,但其强大的能力可以为业务带来的各种体验上的优化,这点已经在阿里内部多个业务上得到了验证。我们期待开发者能在自己的业务中引入这项技术,如果您发现使用中出现了问题,使用中发现了需要内核优化的场景,使用中发现了新的需求,都可以联系我们。U4 内核技术团队愿意在提升 Web 能力上投入自己的技术力量并做出贡献。