当前web应用在移动时代并无达到其在桌面设备上流行的程度,下面有张图来对比与原生应用之间的差异。
究其缘由,无外乎下面不可避免的几点:css
假如能解决以上的几点,对web app 来讲会有多大的提高能够想象。html
PWA 全称Progressive Web Apps(渐进式Web应用程序),旨在使用现有的web技术提供用户更优的使用体验。
基本要求java
PWA 自己强调渐进式,并不要求一次性达到安全、性能和体验上的全部要求,开发者能够经过 PWA Checklist 查看现有的特征。 git
除以上的基准要求外,还应该包括如下特性:github
看起来有点眼花缭乱,这又是一个新的飞起的轮子吗?这里重申一下,PWA背后不是一种新的技术,而是集合当前多种web技术的一种集合。分别利用各自的功能来完成渐进式的总体需求。下面就沿着前面提出的问题分别了解一下相关技术web
由如下几种技术构成:chrome
其中Service Worker是PWA技术的关键,它们可让app知足上面的三基准。其余技术则是锦上添花,让app更加的强大。json
针对网页的体验,从前到后都作了不少努力,极力去下降响应时间,这里就不表述多样的技术手段。
另外一个方向的就是缓存,减小与服务器非必要的交互,不过对于离线的状况下浏览器缓存就无力了,
这样离线缓存的需求就出现了。数组
web应用在离线缓存发展的过程当中也不是一簇而就的,经历了逐渐完善的过程。
初期的解决方案是AppCache
然而,事实证实这是一个失败的尝试,缺陷太多,已经被废弃了。具体能够查看Application Cache is a douchebag
可是方向仍是正确的,那就继续孜孜不倦的探索。promise
持久化先放一边,来谈谈另外一个问题
基于浏览器中的 javaScript 单线程的现实逐渐不能知足现代web需求的现状,例如耗时的计算,用户的交互显然会受影响。
为了将这些耗时操做从主线程中解放出来,早期W3C新增了一个Web Worker 的 API,能够脱离主线程单独执行,而且能够与主线程交互。
不过Web Worker是临时性的依赖于建立页面 ,不能知足咱们持久化的需求。
冲着这个目标,下面就比较容易解决了,搞个能持久存在的就好了。
在Web Worker的基础上,W3C新增了service worker来知足咱们持久化的需求。
其生命周期与页面无关,关联页面未关闭时,它也能够退出,没有关联页面时,它也能够启动
功能
Service Worker虽然知足了离线缓存来,其功能可不只仅局限于此。 能够提供
这些正好也是PWA的目的,因此说Service Worker是PWA的关键技术。
Service Worker 出于安全性和其实现原理,在使用的时候有必定的前提条件。
由上可知,不是全部的浏览器都支持的,支持状况大概以下:
iOS 内的全部的浏览器都基于 safari,因此iOS要在11.3以上
IE是放弃支持了,不过Edge好歹支持了。
Cache是Service Worker衍生出来的API,配合Service Worker实现对资源请求的缓存。
不过cache并不直接缓存字符串,而是直接缓存资源请求(css、js、html等)。
cache也是key-value形式,通常来讲key就是request,value就是response
注册即声明sw文件的位置,显然应该在主js中引入。大概以下:
//基于promise function registerServiceWorker(){ // 注册service worker return navigator.serviceWorker.register('./sw1.js').then(registration => { console.log('注册成功'); // 返回 return registration; }) .catch(err => { console.error('注册失败', err); }); } window.onload = function () { //是否支持 if (!('serviceWorker' in navigator)) { return; } registerServiceWorker() }
Service worker 有一个独立于web 页面的生命周期。
若是在网站上安装 serice worker ,你须要注册,注册后浏览器会在后台安装 service worker。而后进入下面的不一样阶段。
激活以后,service worker 将控制全部的页面,归入它的范围,不过第一次在页面注册 service worker 时不会控制页面,直到它再次加载。
service worker 生效以后,它会处于下面两种状态之一:
由上图看知,分为这么几个阶段:
了解声明周期实际上是为了咱们在不一样时间段去监听事件来完成相应操做。对PWA来讲主要两个事件。
event.waitUntil():传入一个 Promise 为参数,等到该 Promise 为 resolve 状态为止。
self.skipWaiting():self 是当前 context 的 global 变量,执行该方法表示强制当前处在 waiting 状态的 Service Worker 进入 activate 状态。
event.waitUntil():传入一个 Promise 为参数,等到该 Promise 为 resolve 状态为止。
self.clients.claim():在 activate 事件回调中执行该方法表示取得页面的控制权, 这样以后打开页面都会使用版本更新的缓存。旧的 Service Worker 脚本再也不控制着页面,以后会被中止。
const CURCACHE = 'CURCACHE_test_1' const RUNTIME = 'runtime'; const CURCACHE_URLS = [ './', '/asset/sw.jpg', 'index.js' ] self.addEventListener('install',e=>{ e.waitUntil( //存储缓存路径对应的资源 caches.open(CURCACHE).then(cache=>{ cache.addAll(CURCACHE_URLS) }).then( self.skipWaiting() ) ) }) //代理请求,使用缓存,请求发送以前 self.addEventListener('fetch', e => { e.respondWith( //缓存是否匹配 caches.match(e.request).then(function(response) { if (response != null) { //命中缓存返回缓存,结束请求 return response } //未命中缓存,正常请求 return fetch(e.request.url) }) ) });
更新service worker
service worker 更新步骤以下:
const CURCACHE = 'precache_test_1' //假设上个版本的key为precache_test_2 反正不等于CURCACHE self.addEventListener('activate', e => { e.waitUntil( //遍历当前缓存keys caches.keys().then(cacheNames=>{ return Promise.all( cacheNames.map(function(cacheName) { //是否等于当前key,保留本身 if (cacheName !== CURCACHE) { return caches.delete(cacheName); } }) )}).then(() => self.clients.claim()) ) })
这样一个简单的service worker离线缓存完成了。控制台能够看到,来源是service worker
关闭网络以后再次访问,能够一样获得上面的结果,而且sw.js请求未能拿到,可是不影响,旧的文件依然在,这里证实了每次都回去对比sw文件以确保更新
到这里,离线缓存就实现了。
容许将站点添加至主屏幕,是 PWA 提供的一项重要功能。这样就不用再依赖于浏览器做为平台,符合移动端的用户习惯。
须要 manifest.json 文件去配置应用的图标、名称等基本信息以下:
{ //被提示安装应用时出现的文本 "name": "PQJ-PWA", //添加至主屏幕后的文本 "short_name":"PQJ", "description": "测试demo", //添加以后,启动地址 "start_url": "/index.html", //图标信息 "icons": { "128": "/asset/sw.jpg" }, "developer": { "name": "pqj", "url": "" }, "display": "standalone", "background_color": "#287fc5", "theme_color": "#fff", "permissions": { "desktop-notification": { "description": "Needed for creating system notifications." } } }
而后以以下方式在html中引入
<link rel="manifest" href="/mainfest.json" />
这样完成以后,移动端安卓使用chrome(亲测),首次访问时会提示是否容许安装到主屏幕,以应用icon的形式出现。
图片和文字即由配置决定。
消息通知也是使用service worker的通知功能进行的,容许服务器想用户发生通知,而非用户主动请求才去响应某些行为。
正常的通知逻辑须要服务器来参与实现,此次展现只实现功能。
function getPermission(){ return new Promise((resolve, reject) => { //权限获取 const permissionPromise = Notification.requestPermission(result => { resolve(result); }); }).then(result => { //判断条件 if (result === 'granted') { execute(); } else { console.log('no permission'); } }); }
发送通知
function execute() { // 容许以后执行 registerServiceWorker().then(registration => { // 通知 registration.showNotification('Hello World!'); }); }
https://lavas.baidu.com/doc
https://developer.mozilla.org/zh-CN/Apps/Progressive
至此,本文介绍就结束了,更多请参考实例虽然PWA目前来看,面对的限制还不少,可是也能够看出web组织在更好的提高web应用方向上作的努力。正如一直提到的那句话,将来可期。目前国内百度这方面作的比较成熟,新浪微博已经有了pwa 测试版。