前言:本示例不用安装任何东西部分资源来自网络资源及PWA官网,不要把PWA想象的太复杂,跟着示例走一下,你行的。javascript
一个新的前端技术,PWA( 全称:Progressive Web App )也就是说这是个渐进式的网页应用程序。css
官网:https://developers.google.com... html
是 Google 在 2015 年提出,2016年6月才推广的项目。是结合了一系列现代Web技术的组合,在网页应用中实现和原生应用相近的用户体验。前端
官网上给出 PWA 的宣传是 : Reliable ( 可靠的 )、Fast( 快速的 )、Engaging( 可参与的 )java
Reliable :当用户从手机主屏幕启动时,不用考虑网络的状态是如何,均可以马上加载出 PWA。git
Fast:这一点应该都很熟悉了吧,站在用户的角度来考虑,若是一个网页加载速度有点长的话,那么咱们会放弃浏览该网站,因此 PWA 在这一点上作的很好,他的加载速度是很快的。web
Engaging : PWA 能够添加在用户的主屏幕上,不用从应用商店进行下载,他们经过网络应用程序 Manifest file 提供相似于 APP 的使用体验( 在 Android 上能够设置全屏显示哦,因为 Safari 支持度的问题,因此在 IOS 上并不能够 ),而且还能进行 ”推送通知” 。npm
如下用SW来表示json
SW 是什么呢?这个是离线缓存文件。咱们 PWA 技术使用的就是它!SW 是浏览器在后台独立于网页运行的脚本,它打开了通向不须要网页或用户交互的功能的大门,由于使用了它,才会有的那个 Reliable 特性吧,SW 做用于 浏览器于服务器之间,至关于一个代理服务器。后端
浏览器支持
顺便带一句:目前只能在 HTTPS 环境下才能使用SW,由于SW 的权利比较大,可以直接截取和返回用户的请求,因此要考虑一下安全性问题。
事件机制
功能(仍是比较逆天的)
生命周期
当前已无激活状态的 worker 、 SW脚本中的 self.skipWaiting()方法被调用 ( ps: self 是 SW 中做用于全局的对象,这个方法根据英文翻译过来也能明白什么意思啦,跳过等待状态 )、用户已关闭 SW 做用域下的全部页面,从而释放了当前处于激活状态的 worker、超出指定时间,从而释放当前处于激活状态的 worker
一个很不错的全面介绍sw的教程:https://www.villainhr.com/page/2017/01/08/Service%20Worker%20%E5%85%A8%E9%9D%A2%E8%BF%9B%E9%98%B6
Web App Manifest 是一个 W3C 规范,它定义了一个基于 JSON 的 List 。Manifest 在 PWA 中的做用有:
可以将你浏览的网页添加到你的手机屏幕上
在 Android 上可以全屏启动,不显示地址栏 ( 因为 Iphone 手机的浏览器是 Safari ,因此不支持哦)
控制屏幕 横屏 / 竖屏 展现
定义启动画面
能够设置你的应用启动是从主屏幕启动仍是从 URL 启动
能够设置你添加屏幕上的应用程序图标、名字、图标大小
Push 和 Notification 是两个不一样的功能,涉及到两个 API 。
Notification 是浏览器发出的通知消息。
Push 和 Notification 的关系,Push:服务器端将更新的信息传递给 SW ,Notification: SW 将更新的信息推送给用户。
准备
咱们先建立一个关于 PWA 的项目文件夹,
进入文件夹下咱们准备一张 120x120的图片一张,做为咱们的应用程序图标。
建立一个 index.html 文件
建立一个 main.css 文件
建立一个 manifest.json 文件
建立一个 sw.js 文件
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Hello PWA</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <link rel="stylesheet" href="main.css"> <link rel="manifest" href="manifest.json"> </head> <body> <h3>Hello PWA</h3> </body> <script> // 检测浏览器是否支持SW if(navigator.serviceWorker != null){ navigator.serviceWorker.register('sw.js') .then(function(registartion){ console.log('支持sw:',registartion.scope) }) } </script> </html>
main.css
h3{ color: #f00; }
manifest.json
short_name: “ " 用户主屏幕上的应用名字
display : “standalone" 设置启动样式,让您的网络应用隐藏浏览器的 URL 地址栏
start_url : “/“ 设置启动网址,若是不提供的话,默认是使用当前页面
theme_color : “ “ 用来告知浏览器用什么颜色来为地址栏等 UI 元素着色
background_color: “ ” 设置启动页面的背景颜色
icons:”” 就是添加到主屏幕以后的图标
{ "name": "一个PWA示例", "short_name": "PWA示例", "start_url": "/index.html", "display": "standalone", "background_color": "#fff", "theme_color": "#3eaf7c", "icons": [ { "src": "/youhun.jpg", "sizes": "120x120", "type": "image/png" } ], }
sw.js
看网上不少人都安装的hs和ngrok去调试,在这里为了照顾新手我是直接引用的sw
处理静态缓存,首先定义须要缓存的路径,以及须要缓存的静态文件的列表。
借助 SW 注册完成安装 SW 时,抓取资源写入缓存中。使用了一个方法那就是 self.skipWaiting( ) ,为了在页面更新的过程中,新的 SW 脚本可以马上激活和生效。
importScripts("https://storage.googleapis.com/workbox-cdn/releases/3.1.0/workbox-sw.js"); var cacheStorageKey = 'minimal-pwa-1' var cacheList=[ '/', 'index.html', 'main.css', 'youhun.jpg' ] self.addEventListener('install',e =>{ e.waitUntil( caches.open(cacheStorageKey) .then(cache => cache.addAll(cacheList)) .then(() => self.skipWaiting()) ) })
处理动态缓存,咱们监听 fetch 事件,在 caches 中去 match 事件的 request ,若是 response 不为空的话就返回 response ,最后返回 fetch 请求,在 fetch 事件中咱们能够手动生成 response 返回给页面。
更新静态资源,缓存的资源会跟随着版本的更新会过时的,因此会根据缓存的字符串名称清除旧缓存。在新安装的 SW 中经过调用 self.clients.claim( ) 取得页面的控制权,这样以后打开页面都会使用版本更新的缓存。旧的 SW 脚本不在控制着页面以后会被中止,也就是会进入 Redundant 期。
self.addEventListener('fetch',function(e){ e.respondWith( caches.match(e.request).then(function(response){ if(response != null){ return response } return fetch(e.request.url) }) ) }) self.addEventListener('activate',function(e){ e.waitUntil( //获取全部cache名称 caches.keys().then(cacheNames => { return Promise.all( // 获取全部不一样于当前版本名称cache下的内容 cacheNames.filter(cacheNames => { return cacheNames !== cacheStorageKey }).map(cacheNames => { return caches.delete(cacheNames) }) ) }).then(() => { return self.clients.claim() }) ) })
部署
咱们能够把当前pwa目录的全部内容都扔进服务器中,或者coding Pages和gitHub Pages也是能够的,固然,记得开启https。在上变介绍过SW的权利比较大,为了安全性,咱们使用https协议来访问。
试着访问一下,咱们这里用的coding Pages而且绑定了本身的域名
打开 chrom 的调试工具,打开 application ,点击 service workers 以后咱们会发现 sw.js 脚本已经存到了 SW 中 。
咱们打开 Network 刷新页面一下,看看,咱们的页面资源来自 SW 而不是其余的地方,在 Console 中也打印出了咱们在 index.html 中判断的语句,浏览器支持就会打印出这一句话。
接下来咱们断网操做,在 Application 中给 Offline 打上对勾就行啦。而后刷新页面,咱们仍然能看到以前的页面,缘由就是咱们在上图看到,他的资源是从 SW 上得到到的。当咱们第一次打开这个页面的时候,Resopnse 对象被存到了 Cache Storage ( 定义在 SW 规范中 ,相关资料请同窗们自行查询啦 )中,咱们看下图:
经过存放到 Cache Storage 中,咱们下次访问的时候若是是弱网或者断网的状况下,就能够不走网络请求,而直接就能将本地缓存的内容展现给用户,优化用户的弱网及断网体验。
这个时候确定会有同窗在想,若是内容更新了,那么页面展现的内容是新内容呢仍是旧内容呢?下面咱们操做一下,打开 index.html 文件,咱们在 body 中添加一个 p 标签 ,而后回到页面刷新。
咱们看到,页面上的内容并无显示出我刚刚添加的那个 p 标签。这说明了,咱们拿到的数据仍是从 Cache Storage 中获取到的,Cache Storage中的内容并无更新,强制刷新也不行哦,那么咱们怎么才能让我刚刚添加的那个 p 标签显示出来呢。
咱们打开 sw.js 脚本文件,咱们修改一下 cacheStorageKey。
修改后,咱们再次打开该网址,强制刷新下或者关掉浏览器从新打开。
页面中出现了刚刚添加的P标签,咱们再看一下 Cache Storage 中的缓存名字,已经被修改。
若是是使用coding或者gitHub提供的pages服务,则须要注意最好绑定下独立域名。若是不绑定则注意下文件请求路径便可。
研究PWA门槛不低,部署的服务器要求HTTPS,ServiceWorker涉及API众多,须要单独学习,另外npm中也已经有这个包了https://www.npmjs.com/package... ,玩玩能够,真正部署到项目生产环境可能坑不少,但有坑填坑,不折腾还叫前端么。