关于PWA

PWA(Progressive Web App), 即渐进式web应用。PWA本质上是web应用,目的是通过多项新技术,在安全、性能、体验等方面给用户原生应用的体验。而且无需像原生应用那样繁琐的下载、安装、升级等操作。

这里解释下概念中的“渐进式”,意思是这个web应用还在不断地进步中。因为目前而言,PWA还没有成熟到一蹴而就的程度,想在安全、性能、体验上达到原生应用的效果还是有很多的提升空间的。一方面是构建PWA的成本问题,另一方面是目前各大浏览器、安卓和IOS系统对于PWA的支持和兼容性还有待提高。

本文我将从网站缓存、http请求拦截、推送到主屏等功能,结合实例操作,一步步引领大家快速玩转PWA技术。

Service Worker

Service Worker是PWA的核心技术,它能够为web应用提供离线缓存功能,当然不仅如此,下面列举了一些Service Worker的特性:

  • 基于HTTPS 环境,这是构建PWA的硬性前提。(LAMP环境网站升级HTTPS解决方案

  • 是一个独立的 worker 线程,独立于当前网页进程,有自己独立的 worker context

  • 可拦截HTTP请求和响应,可缓存文件,缓存的文件可以在网络离线状态时取到

  • 能向客户端推送消息

  • 不能直接操作 DOM

  • 异步实现,内部大都是通过 Promise 实现

Service Worker生命周期

serviceworker的使用流程可以简单总结为注册--安装--激活。

注册

注册其实就是告诉浏览器serviceworkerJS文件存放在什么位置,然后浏览器下载、解析、执行该文件,进而启动安装。这里我创建一个app.js文件,注册代码如下,将该文件在网站的head标签里引入。

if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('/sw.js')
.then(function (registration) {
// 注册成功
console.log('ServiceWorker registration successful with scope: ', registration.scope);
})
.catch(function (err) {
// 注册失败:(
console.log('ServiceWorker registration failed: ', err);
});
});
}

安装

当执行serviceworkerJS文件时,首先触发的是install事件,进行安装。安装的过程就是将指定的一些静态资源进行离线缓存。下面是我的sw.js文件中的安装代码:

var CACHE_VERSION = 'sw_v8';
var CACHE_FILES = [
'/js/jquery/min.js',
'/js/zui/min.js',
'/js/chanzhi.js',
];
self.addEventListener('install', function (event) {
event.waitUntil(
caches.open(CACHE_VERSION)
.then(cache => cache.addAll(CACHE_FILES)
));
});

激活

当安装成功后,serviceworker就会激活,这时就会处理 activate 事件回调 (提供了更新缓存策略的机会)。并可以处理功能性的事件 fetch (请求)、sync (后台同步)、push (推送)。

self.addEventListener('activate', function (event) {
event.waitUntil(
caches.keys().then(function(keys){
return Promise.all(keys.map(function(key, i){
if(key !== CACHE_VERSION){
return caches.delete(keys[i]);
}
}));
})
);
});

serviceworker的缓存功能

安装时,serviceworker将我们指定的静态资源进行缓存(即预缓存),你也许会问,如果是实时的动态内容怎么办,我们不可能预先将所有的文件资源提前指定好,让serviceworker缓存。这就要提到serviceworker的拦截HTTP请求响应的特性了。

serviceworker拦截http请求,首先去检查请求的资源在缓存中是否存在,如果存在,则直接从缓存中调用,而且即便是无网络情况下,serviceworker也能调用缓存中的资源。如果缓存中没有请求的资源,则通过网络去服务器上检索,而且在找到并响应时,serviceworker会将其存入缓存中,以备下次再请求时直接从缓存中调用。

serviceworker缓存流程

serviceworker文件中fetch事件代码如下:

self.addEventListener('fetch', function (event) {
event.respondWith(
caches.match(event.request).then(function(response){
if(response){
return response;
}
var requestToCache = event.request.clone();
return fetch(requestToCache).then(
function(response){
if(!response || response.status !== 200){
return response;
}
var responseToCache = response.clone();
caches.open(CACHE_VERSION)
.then(function(cache){
cache.put(requestToCache, responseToCache);
});
return response;
}
);
})
);
});

在网站前台通过浏览器开发者工具,我们可以看下从缓存中调用资源的效果:

我这里操作演示用的是谷歌浏览器,下面是各大浏览器对于serviceworker的支持情况:

serviceworker浏览器支持情况

添加到主屏

PWA支持将web应用在主屏桌面上添加一个快捷方式,以方便用户快速访问,同时提升web应用重复访问的几率。你也许会说,现在移动端上的浏览器功能列表里一般都提供了“添加到桌面”的功能呀,但是PWA与浏览器自带的添加到桌面的实现方式不同。

PWA不需要用户刻意去功能列表中使用这个功能按钮,而是在用户访问web应用时,直接在界面中提示一个添加到主屏桌面的横幅,从web应用角度而言,这其实就是主动与被动的区别。

PWA实现该功能非常简单,只需要一个manifest.json文件,文件中用户可以自定义应用的启动页面、模板颜色、图标等内容。下面是我的manifest.json文件设置,大家可作参考:

{
"short_name": "蝉知资源站",
"name": "蝉知资源站",
"icons": [
{
"src": "chanzhiicon.png",
"type": "image/png",
"sizes": "48x48"
},
{
"src": "192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "512.png",
"type": "image/png",
"sizes": "512x512"
},
{
"src": "144.png",
"type": "image/png",
"sizes": "144x144"
}
],
"start_url": "/index.html",
"display": "standalone",
"background_color": "#2196F3",
"orientation": "landscape",
"theme_color": "#2196F3"
}

需要提醒的是,目前移动端IOS系统的支持并不好,安卓手机上须使用57版本以上的谷歌浏览器可以支持该功能,下面是我在安卓手机上的操作演示:

添加到主屏

小结

PWA技术正被广大企业及开发者们关注,虽然目前各设备的支持兼容有待提高,但这些都正在不断的改善进步。我也相信在不久的将来,PWA技术会逐步广泛普及,为广大企业和用户带来便利。本文和大家一起分享了PWA的相关技术与实例操作,后面还会就消息推送、数据同步等功能做进一步探讨交流。如果大家在学习PWA的过程中遇到其他问题,欢迎一起讨论交流。

更多技术文章,欢迎关注公众号:

干货 | 10分钟玩转PWA的更多相关文章

  1. 干货 | 10分钟教你用column generation求解vehicle routing problems

    OUTLINE 前言 VRPTW description column generation Illustration code reference 00 前言 此前向大家介绍了列生成算法的详细过程, ...

  2. 干货 | 10分钟带你彻底了解column generation(列生成)算法的原理附java代码

    OUTLINE 前言 预备知识预警 什么是column generation 相关概念科普 Cutting Stock Problem CG求解Cutting Stock Problem 列生成代码 ...

  3. Docker系列之(一):10分钟玩转Docker(转)

    1.前言 进入云计算的时代,各大云提供商AWS,阿里云纷纷推出针对Docker的服务,现在Docker是十分火爆,那么Docker到底是什麽,让我们来体验一下. 2.Docker是什麽 Docker是 ...

  4. Redis系列之(一):10分钟玩转Redis(转)

    1. Redis介绍 Redis是一个开源的使用ANSI C语言编写.基于内存的Key-Value数据库. 它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集 ...

  5. Docker系列之(一):10分钟玩转Docker

    1.前言 进入云计算的时代,各大云提供商AWS,阿里云纷纷推出针对Docker的服务,现在Docker是十分火爆,那么Docker到底是什麽,让我们来体验一下. 2.Docker是什麽 Docker是 ...

  6. Redis系列之(一):10分钟玩转Redis

    1. Redis介绍 Redis是一个开源的使用ANSI C语言编写.基于内存的Key-Value数据库. 它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集 ...

  7. mongoDB系列之(一):10分钟玩转mongoDB

    1. mongoDB是什麽 mongodb是时下流行的NoSql数据库,它的存储方式是文档式存储,并不是Key-Value形式. 存储在集合中的文档,被存储为键-值对的形式.键用于唯一标识一个文档,为 ...

  8. Docker学习总结(10)——10分钟玩转Docker

    1.前言 进入云计算的时代,各大云提供商AWS,阿里云纷纷推出针对Docker的服务,现在Docker是十分火爆,那么Docker到底是什麽,让我们来体验一下. 2.Docker是什麽 Docker是 ...

  9. 干货 | 10分钟带你全面掌握branch and bound(分支定界)算法-概念篇

    00 前言 之前一直做启发式算法,最近突然对精确算法感兴趣了.但是这玩意儿说实话是真的难,刚好boss又叫我学学column generation求解VRP相关的内容.一看里面有好多知识需要重新把握, ...

随机推荐

  1. AND 初识

    框架

  2. java-框架-索引

    spring 整体了解 spring 入门demo Spring整体了解 spring梳理 Spring线程池的5个要素 spring的事务隔离级别以及传播性 事务4个隔离界别及脏读,不可重复读,幻读 ...

  3. Vue.js中记不住 的东西

    给样式背景赋值: :style="{backgroundImage:'url(' + otherInfo.head_image + ')'}" <img :src=" ...

  4. HttpLogBrowser-GUI日志分析工具

    登陆https://www.iis.net/downloads搜索HttpLogBrowser获得最新版本

  5. Servlet学习记录4

    带进度条的文件上传 UploadServlet只实现了普通的文件上传,并附带普通文本域的提交.如果需要显示上传进度条,实时显示上传速度等,需要配合使用Ajax技术.这里仍然使用Apache的commo ...

  6. 解决easyUI中翻页后前面已钩选项自动变为未选择的问题

    在easyUI的datagrid中,必须在属性的第一条就要写 idField:'id' (只要创建数据表格,就必须要加idField),其中id是页面数据的主键名称. 这样设置之后,表格翻页之后,前面 ...

  7. JQuery+formValidator实现表单验证

    <!-- 需求: 用户注册页面要有用户名.密码.确认密码.邮箱 用户名文本框:用户名不能为空,且必须为数字与字母的6到12位的组合 密码框:密码不能为空,最少6位,包括至少1个大写字母,1个小写 ...

  8. Lua + Redis 解决高并发

    一.业务背景 优惠券业务主要提供用户领券和消券的功能:领取优惠券的动作由用户直接发起,由于资源有限,我们必须对用户的领取动作进行一些常规约束. 约束1(优惠券维度): 券的最大数量 max: 约束2( ...

  9. C10K

    参考 https://www.jianshu.com/p/ba7fa25d3590

  10. 关于Collections.sort()排序方法的源码探索

    /**下面在自己代码中使用Collections.sort()方法去比较Student对象,通过在自己写的类里面通过匿名内部类实现Comparator接口,这个接口是让你自己实现比较器的规则*/ // ...