什么是 PWA
PWA 全称 Progressive Web Apps(渐进式 Web 应用程序),旨在使用现有的 Web 技术提供用户更优的使用体验。
基本要求
可靠(Reliable)一方面是指PWA的安全性,PWA只能运行在HTTPS上;另一方面是指在网络不稳定或者没网情况下,PWA依然可以访问。快速响应(Fast)快速响应用户的交互行为,并且具有平滑流畅的动画、加载速度、渲染速度和渲染性能等。粘性(Engaging)通过添加到桌面以及离线消息推送,能带来用户的第二次访问,并且依靠良好的用户体验吸引用户再次访问。
官网链接:Progressive Web Apps
PWA 的核心技术
PWA 不是一项单独的技术,技术包括 Manifest、Service Worker、Push API & Notification API 、App Shell & App Skeleton 等等技术,接下来我们重点介绍几项技术以及相关问题的解决方法。
manifest
manifest 是支持站点在主屏上创建图标的技术方案,并且定制 PWA 的启动画面的图标和颜色等,如下图:
chrome > 桌面图标 > 启动样式 > 打开效果
manifest 内容
1 | { |
manifest 属性
name— 网页显示给用户的完整名称;short_name— 这是为了在没有足够空间显示Web应用程序的全名时使用;description— 关于网站的详细描述;start_url— 网页的初始相对URL比如/)display— 应用程序的首选显示模式;fullscreen- 全屏显示;standalone- 应用程序将看起来像一个独立的应用程序;minimal-ui- 应用程序将看起来像一个独立的应用程序,但会有浏览器地址栏;browser- 该应用程序在传统的浏览器标签或新窗口中打开.
orientation— 应用程序的首选显示方向;anynaturallandscapelandscape-primarylandscape-secondaryportraitportrait-primaryportrait-secondary
background_color— 启动屏的背景颜色;theme_color— 网站的主题颜色;icons— 定义了src、sizes和type的图片对象数组,各种环境中用作应用程序图标的图像对象数组.
MDN提供了完整的manifest属性列表: Web App Manifest properties
manifest 使用
manifest功能虽然强大,但是技术上并不难,就是一个外链的json文件,通过link来引入:
1 | <!-- 在 html 页面中添加以下 link 标签 --> |
manifest 验证
在开发者工具中的 Application Tab 左边有 Manifest 选项,你可以验证你的 manifest JSON 文件,并提供了 “Add to homescreen” .

Service Worker
Service Worker 是 PWA 中最重要的概念之一,它是一个特殊的 Web Worker,独立于浏览器的主线程运行,特殊在它可以拦截用户的网络请求,并且操作缓存,还支持 Push 和后台同步等功能。
注册服务
在 install Service Worker 之前,要在主进程 JavaScript 代码里面注册它,注册是为了告诉浏览器我们的 Service Worker 文件是哪个,然后在后台,Service Worker 就开始安装激活。
1 | if ("serviceWorker" in navigator) { |
注册时,还可以指定可选参数 scope,scope 是 Service Worker 可以以访问到的作用域,或者说是目录。
1 | navigator.serviceWorker.register("/sw.js", { |
注册成功后,您可以通过转至 chrome://inspect/#service-workers 并寻找您的网站来检查 Service Worker 是否已启用。

安装 Service Worker 服务
install 事件绑定在 Service Worker 文件中,当安装成功后,install 事件就会被触发。
一般我们会在 install 事件里面进行缓存的处理,用到之前提到的 Cahce API,它是一个 Service Worker 上的全局对象,可以缓存网络相应的资源,并根据他们的请求生成 key,这个 API 和浏览器标准的缓存工作原理相似,但是只是针对自己的 scope 域的,缓存会一直存在,知道手动清楚或者刷新。
1 | const cacheName = "bs-0-0-1"; // 缓存名称 |
更新 Service Worker 服务
当你的 Service Worker 需要更新时, 需要经过以下步骤
- 更新您的服务工作线程
JavaScript文件。 用户导航至您的站点时,浏览器会尝试在后台重新下载定义Service Worker的脚本文件。 如果Service Worker文件与其当前所用文件存在字节差异,则将其视为新 Service Worker。 - 新
Service Worker将会启动,且将会触发install事件。 - 此时,旧
Service Worker仍控制着当前页面,因此新Service Worker将进入waiting状态。 - 当网站上打开的页面关闭时,旧
Service Worker将会被终止,新Service Worker将会取得控制权。 - 新
Service Worker取得控制权后,将会触发其activate事件。
如果希望在有了新版本时,所有的页面都得到及时自动更新怎么办呢?可以在 install 事件中执行 self.skipWaiting() 方法跳过 waiting 状态,然后会直接进入 activate 阶段。接着在 activate 事件发生时,通过执行 self.clients.claim() 方法,更新所有客户端上的 Service Worker。
当 Service Worker 安装完成后并进入激活状态,会触发 activate 事件。通过监听 activate 事件你可以做一些预处理,如对旧版本的更新、对无用缓存的清理等。
1 | // 监听 activate 事件,激活后通过cache的key来判断是否更新、删除 cache 中的静态资源 |
处理动态请求缓存
在 Service Worker 的作用域中,当有网络请求时发生时,fetch 事件将被触发。它调用 respondWith() 方法来劫持网络请求缓存并返回:
1 | var apiCacheName = "api-0-1-1"; |
到这里,离线缓存动静态资源就完成了。

使用 Lighthouse 测试我们的应用
至此,我们完成了 PWA 的两大基本功能:Web App Manifest 和 Service Worker 的离线缓存。这两大功能可以很好地提升用户体验与应用性能。我们用 Chrome 中的 Lighthouse 来检测一下目前的应用:
可以看到,在 PWA 评分上,我们的这个 WebApp 已经非常不错了。
完整代码 -> 梦魇小栈 PWA 完整代码
1 | var cacheName = "bs-0-0-2"; |
由于现在博客仅需 Manifest、Service Worker 后面的技术、Push API & Notification API 、App Shell & App Skeleton 等打算以后有时间在考虑场景加上~
