PWA的探索与应用
本文由云+社区发表
PWA(Progressive Web App)起源背景
传统的Web网页存在以下几个问题:
- 进入一个页面必须要记住它的url或者加入书签,入口不便捷;
- 没网络就没响应,不具备离线能力;
- 不像APP一样能进行消息推送。
Native app:
- 开发成本高
- 软件上线需要审核
- 即使使用频率不高,想使用一个app必须先下载安装
PWA概念的提出
2016 年Google I/O 大会上提出一个 Next Web Generation 的概念。PWA是在传统Web应用的基础上,结合Manifest和service worker,完善Web应用的一些能力,比如:
- 添加至主屏幕,点击主屏幕图标可以实现启动动画以及隐藏地址栏
- 实现离线缓存功能,即使用户手机没有网络,依然可以使用一些离线功能
- 消息推送
PWA技术点
Web App Manifest
Web App Manifest 技术实现了将PWA网页应用 添加至桌面的功能,但该项技术目前仍处于实验性阶段,各浏览器支持度不高
image.png
PWA 站点部署的 manifest.json文件满足以下条件时会自动显示横幅:
- short\\_name (主屏幕显示)
- name (安装横幅显示)
- icons (必须包含一个 mime 类型为 image/png 的图标声明)
- start\\_url (应用启动地址)
- display (必须为 standalone 或 fullscreen)
- 站点注册 Service Worker。
- 站点支持 HTTPS 访问。
- 同一浏览器中站点至少被访问两次,间隔至少为 5 分钟。
Service Worker
PWA应用的离线体验、定期的后台同步以及推送通知等功能的实现依赖于Service Worker技术,下图为目前SW技术的支持度。

SW具有以下特征:
- 一个独立的 worker 线程,独立于当前网页进程,有自己独立的 worker context。
- 一旦被 install,就永远存在,除非被手动 unregister
- 用到的时候可以直接唤醒,不用的时候自动睡眠
- 离线内容开发者可控
- 能向客户端推送消息
- 不能直接操作 DOM
- 必须在 HTTPS 环境下才能工作
- 异步实现,内部大都是通过 Promise 实现
Service Worker生命周期

- installing:这个状态发生在 SW 注册之后开始安装,install 事件回调中执行skipWaiting()方法表示强制当前处在 waiting 状态的 Service Worker 进入 activate 状态。
- installed:SW已经完成了安装,等待其他的 SW 线程被关闭。
- activating:在这个状态下清除其他的worker 以及关联缓存的旧缓存资源,等待新的 SW线程被激活。在 activate 事件回调中执行self.clients.claim()方法表示取得页面的控制权, 这样之后打开页面都会使用版本更新的缓存。旧的 Service Worker 脚本不再控制着页面,之后会被停止。
- activated:在这个状态可以处理功能性的事件 fetch (请求)、sync (后台同步)、push (推送)。
- 废弃状态 ( redundant ):这个状态表示一个 Service Worker 的生命周期结束。
Service Worker 支持的事件

- install:Service Worker 安装成功后被触发的事件, 在事件处理函数中可以添加需要缓存的文件
- activate:当 Service Worker 安装完成后并进入激活状态,会触发 activate 事件。通过监听 activate 事件你可以做一些预处理,如对旧版本的更新、对无用缓存的清理等。
- message:Service Worker 运行于独立 context 中,无法直接访问当前页面主线程的 DOM 等信息,但是通过 postMessage API,可以实现他们之间的消息传递,这样主线程就可以接受 Service Worker 的指令操作 DOM。
- fetch :当浏览器在当前指定的 scope 下发起请求时,会触发 fetch 事件,并得到传有 response 参数的回调函数。fetch 事件特别重要,因为它能够定义你的缓存策略。也就是说,你可以决定何时使用缓存数据,何时使用网络请求来的数据。
- push:push 事件是为推送准备的。通过 PUSH API,当订阅了推送服务后,可以使用推送方式唤醒 Service Worker 以响应来自系统消息传递服务的消息,即使用户已经关闭了页面。
- sync:sync 事件由 background sync (后台同步)发出。background sync 是 Google 配合 SW 推出的 API,用于为 Service Worker 提供一个可以实现注册和监听同步处理的方法。但它还不在 W3C Web API 标准中。在 Chrome 中这也只是一个实验性功能,需要访问 chrome://flags/#enable-experimental-web-platform-features ,开启该功能,然后重启生效。Sync 事件允许延迟网络任务,直到用户连接上网络,它实现的功能通常被称为后台同步。这对于在离线模式下,确保用户启动的任何有网络依赖的任务,最终都将在网络再次可用时达到其预期目的,是非常有用的。
Service Worker 的工作原理
Service Worker是基于注册、安装、激活等步骤
注册
if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('/jslearning/sw.js') // 默认作用域为jslearning下,也可以通过设置scope参数进行设置
.then(function (registration) {
// 注册成功
console.log('ServiceWorker registration successful with scope: ', registration.scope);
})
.catch(function (err) {
// 注册失败:(
console.log('ServiceWorker registration failed: ', err);
});
});
}
安装
this.addEventListener('install', function(event) {
console.log('V1 installing…');
//需要缓存的重要的高优先级资源
var vipUrlsToPrefetch = [
'./index.html'
];
//次重要的资源
var urlsToPrefetch = [
'./icon.png'
];
event.waitUntil(
caches.open(OFFLINE_CACHE_NAME).then(function(cache) {
//urlsToPrefetch非重要资源,即使有资源加载失败也不影响Service Worker安装
cache.addAll(urlsToPrefetch);
//vipUrlsToPrefetch中资源全部请求成功,Service Worker安装事件才顺利完成,可以进入激活事件
return cache.addAll(vipUrlsToPrefetch);
})
);
});
激活
//Service Worker激活事件
this.addEventListener('activate', function(event) {
//在激活事件中清除非当前版本的缓存避免用户存储空间急剧膨胀
event.waitUntil(caches.keys().then(function(cacheNames) {
console.log('V1 activate');
return Promise.all(cacheNames.map(function(cacheName) {
if (cacheName !== OFFLINE_CACHE_NAME) {
if(cacheName.indexOf(OFFLINE_CACHE_PREFIX) != -1) {
return caches.delete(cacheName);
}
}
}));
}));
});
Service Worker更新
- 如果线程的字节与已有的SW线程字节不同,浏览器则考虑更新SW线程。
- 更新的SW线程与现有SW线程一起启动,并获取自己的 install 事件。
- 如果新工作SW线程出现不正常状态代码(例如,404)、解析失败,在执行中引发错误或在安装期间被拒,则系统将舍弃新工作线程,但当前工作线程仍处于活动状态。
- 安装成功后,更新的工作线程将 wait,直到现有工作线程控制0个客户端。
- self.skipWaiting() 可跳过等待情况,这意味着sw线程在安装完后立即激活。
Service Worker缓存策略
Service Worker缓存策略大部分在fetch与install时间中定义,对于某些固定不变的静态资源,可以在Service Worker初次安装的install事件中将其缓存,但资源过大或者网络不佳都会造成资源并未全部下载成功而导致Service Worker安装被中断安装失败。SW主要有以下几类缓存策略:
- 不影响安装的资源预缓存
- 渐进式缓存
- 仅使用缓存、仅使用网络
- 缓存优先 、网络优先
// 渐进式缓存
var addToCache = function(req) {
return fetch(req.clone()).then(function(resp) {
var cacheResp = resp.clone();
if (!resp.ok) {
return resp;
}
caches.open(OFFLINE_CACHE_NAME).then(function(cache) {
cache.put(req.clone(), cacheResp);
});
return resp;
});
};
this.addEventListener('fetch', function(event) {
event.respondWith(
caches.open(OFFLINE_CACHE_NAME).then(function(cache) {
return cache.match(event.request);
}).then(function(response) {
if (response) {
return response;
} else {
return addToCache(event.request);
}
})
);
});
PWA应用可以通过开发者工具中的Application进行查看调试,如下图所示:

PWA优缺点总结
优点
- 可以将app的快捷方式放置到桌面上,全屏运行,与原生app无异
- 能够在网络差和断网条件下
- 推送消息的能力
- 快速响应用户指令
缺点
- 支持率不高
- Chrome在安卓移动端上的占有率很低
- 依赖的GCM服务在国内无法使用
- 微信小程序的竞争
PWA应用
- Lavas 是一套基于 Vue 的 PWA 解决方案,能够帮助开发者快速搭建 PWA 应用
- 新浪微博
- 饿了么
- Offline Wikipedia
- Spotlight
- ...
参考文献
- https://developers.google.com/web/progressive-web-apps/
- https://developer.mozilla.org/en-US/docs/Web/Apps/Progressive
- https://lavas.baidu.com/pwa
- https://x5.tencent.com/tbs/guide/serviceworker.html
- https://segmentfault.com/a/1190000012353473#articleHeader0
- https://blog.csdn.net/baidu_browser/article/details/64440238
此文已由作者授权腾讯云+社区在各渠道发布
获取更多新鲜技术干货,可以关注我们腾讯云技术社区-云加社区官方号及知乎机构号
PWA的探索与应用的更多相关文章
- 让老板虎躯一震的前端技术,KPI杀手
本文由云+社区发表 作者:思衍Jax 天下武功,唯 (wei) 快(fu) 不(bu) 破(po). 随着近几年的前端技术的高速发展,越来越多的团队使用 React.Vue 等 SPA 框架作为其主要 ...
- qconbeijing2018
https://2018.qconbeijing.com/schedule 会议 · 第一天 (2018/04/20 周五) 时间 日程 上午 主题演讲 大数据下的软件质量建设实践 黄闻欣 出品 人工 ...
- 前端应该了解的PWA
一.传统web 应用 当前web应用在移动时代并没有达到其在桌面设备上流行的程度,下面有张图来对比与原生应用之间的差别. 究其原因,无外乎下面不可避免的几点: 移动设备网络限制-不可忽略的加载时间 w ...
- 【探索】机器指令翻译成 JavaScript
前言 前些时候研究脚本混淆时,打算先学一些「程序流程」相关的概念.为了不因太枯燥而放弃,决定想一个有趣的案例,可以边探索边学. 于是想了一个话题:尝试将机器指令 1:1 翻译 成 JavaScript ...
- 【探索】利用 canvas 实现数据压缩
前言 HTTP 支持 GZip 压缩,可节省不少传输资源.但遗憾的是,只有下载才有,上传并不支持.如果上传也能压缩,那就完美了.特别适合大量文本提交的场合,比如博客园,就是很好的例子. 虽然标准不支持 ...
- 探索C#之6.0语法糖剖析
阅读目录: 自动属性默认初始化 自动只读属性默认初始化 表达式为主体的函数 表达式为主体的属性(赋值) 静态类导入 Null条件运算符 字符串格式化 索引初始化 异常过滤器when catch和fin ...
- Mysql事务探索及其在Django中的实践(二)
继上一篇<Mysql事务探索及其在Django中的实践(一)>交代完问题的背景和Mysql事务基础后,这一篇主要想介绍一下事务在Django中的使用以及实际应用给我们带来的效率提升. 首先 ...
- Linux学习之探索文件系统
Linux,一起学习进步- ls With it, we can see directory contents and determine a variety of important file ...
- 马里奥AI实现方式探索 ——神经网络+增强学习
[TOC] 马里奥AI实现方式探索 --神经网络+增强学习 儿时我们都曾有过一个经典游戏的体验,就是马里奥(顶蘑菇^v^),这次里约奥运会闭幕式,日本作为2020年东京奥运会的东道主,安倍最后也已经典 ...
随机推荐
- html2canvas在Vue项目踩坑-生成图片偏移不完整
背景 最近做一个Vue项目需求是用户长按保存图片,页面的数据是根据不同id动态生成的,页面渲染完生成内容图片让用户长按保存的时候,把整个页面都保存起来. 在项目遇到的坑是图片能生成,可是生成的图片总是 ...
- elasticsearch简单操作
现在,启动一个节点和kibana,接下来的一切操作都在kibana中Dev Tools下的Console里完成 创建一篇文档 将小黑的小姨妈的个人信息录入elasticsearch.我们只要输入 PU ...
- python中的矩阵、多维数组
2. 创建一般的多维数组 import numpy as np a = np.array([1,2,3], dtype=int) # 创建1*3维数组 array([1,2,3]) type(a ...
- sketch2code 有的叫screenshot to code什么的
先mark一下项目,回头再深究 https://github.com/mzbac/sketch2code https://www.floydhub.com/emilwallner/datasets/h ...
- git教程——安装配置
Git(读音为/gɪt/.)是一个开源的分布式版本控制系统,可以有效.高速的处理从很小到非常大的项目版本管理. Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个 ...
- Gradle 学习一
参考教程:https://guides.gradle.org/consuming-jvm-libraries/ 安装Gradle 下载地址:https://guides.gradle.org 配置环境 ...
- 已知一个字符串S 以及长度为n的字符数组a,编写一个函数,统计a中每个字符在字符串中的出现次数
import java.util.Scanner; /** * @author:(LiberHome) * @date:Created in 2019/3/6 21:04 * @description ...
- JSON File Parse
1.write a json file base on website(在网站上写一个json文件) json文件网址:https://raw.githubusercontent.com/DJOSIM ...
- 常见的java设计模式
单例模式 简单点说,就是一个应用程序中,某个类的实例对象只有一个,你没有办法去new,因为构造器是被private修饰的,一般通过getInstance()的方法来获取它们的实例. getInstan ...
- LeetCode题解41.First Missing Positive
41. First Missing Positive Given an unsorted integer array, find the first missing positive integer. ...