一、基本介绍
1.1 介绍
- PWA:渐进式web应用,MDN地址: 渐进式 Web 应用(PWA) | MDN (mozilla.org)
- Progressive Web APP,简称 PWA,是提升 Web App的体验的一种新方法,能给用户原生应用的体验。
- PWA 运用现代的 Web API 以及传统的渐进式增强策略来创建跨平台 Web应用程序。
- PWA能做到原生应用的体验不是靠特指某一项技术,而是经过应用一些新技术进行改进
- 只要你拥有一个webapp,那么PWA的旅程就开始了
- 现在 vue 和 react 的脚手架中都已经集成了PWA功能,你还在等什么?
1.2 优势
渐进式-适用于所有浏览器,因为它是以渐进式增强作为宗旨开发的流畅-能够借助Service Worker在离线或者网络较差的情况下正常访问可安装-用户可以添加常用的webapp到面,免去去应用商店下载的麻烦原生体验-可以和app一样,拥有首屏加载动画,可以隐藏地址栏等沉浸式体验。粘性-通过推送离线通知等,可以让用户回流
二、核心技术
-
web app manifest是PWA技术集合中的一部分
-
web app manifest可以让网站安装到设备的主屏幕,而不需要用户通过应用商店进行下载
-
web app manifest,在一个
JSON文本文件中提供有关应用程序的信息(如名称,作者,图标和描述) -
传统的web app入口:1.网址 2.书签,收藏夹 3.直接搜索
-
Web app manifest:
可以添加到桌面,有唯一的图标和名称
有启动时界面,避免生硬的过渡
隐藏浏览器相关的UI,比如地址栏等
2.1 manifest 使用步骤
- 在项目根目录下创建一个 manifest.json 文件
- 在 index.html 中引入 manifest.json 文件
- 在 manifest.json 文件中提供常见的配置
- 需要在 https 协议或者 http://localhost 下访问项目
<link rel="manifest" href="manifest.json" />
创建 index.html
<html>
<head>
<!-- 引入 manifest 配置 -->
<link rel="manifest" href="manifest.json"></link>
</head>
<body>
<div>hello world</div>
</body>
</html>
创建 manifest.json
{
"name":"myapp"
}
控制台输入npm install http-server -g
启动服务,控制台输入http-server
2.2 manifest.json 常见配置
-
name: 用于指定应用的名称,用户安装横幅提示的名称,和启动画面中的文 -
shortname: 应用的短名称,用于主屏幕显示 -
start_url:指定用户从设备启动应用程序时加载的URL。可以是绝对路径和相对路径 -
icons: 用于指定可在各种环境中用作应用程序图标的图像对象数组,144x144 -
background_color: 用户指定启动动画的背景颜色 -
theme_color: 用于指定应用程序的主题颜色 -
display: 用于指定app的显示模式fullscreen全屏显示,所有可用的显示区域都被使用,并且不显示状态栏standalone让这个应用看起来像一个独立的应用程序,包括具有不同的窗口,在应用程序启动器中拥有自己的图标等。minimal-ui该应用程序将看起来像一个独立的应用程序,但会有浏览器地址栏。
2.3 service worker
2.3.1 基础介绍
-
一个标准的PWA程序,必须包含3个部分
https服务器或者 http://localhost
emanifest.json
service worker
-
W3C组织早在 2014年5月就提出过Service Worker 这样的一个HTML5API,主要用来做持久的离线缓存。
-
前端有很多性能优化的手段: CDN、CSS Sprite、文件的合并压缩、异步加载、资源缓存等等,这些手段都是用来做性能优化的,但是如果断网了,会发生什么?
-
service worker允许web应用在网络环境比较差或者是离线的环境下依旧可以使用
-
service worker可以极大的提升web app的用户体验
-
service worker是一个独立的 worker 线程,独立于当前网页进程,是一种特殊的web worier
2.3.2 service worker 介绍
- 浏览器中的javaScript 都是运行在一个单一主线程上的,在同一时间内只能做一件事情
- 随着Web业务不断复杂,我们逐渐在is中加了很多耗资源、耗时间的复杂运算过程,如果在主线程中计算,就会造成性能问题
- w3c提供了web worker的api, Web Worker是脱离在主线程之外的,将一些复杂的耗时的活交给它干
- 完成后通过 postMessage方法告诉主线程
- Web worker是一个独立的运行环境,不能操作DOM和BOM
2.3.3 web worker 使用
- 创建web worker:
- var worker = new Worker('work.js')
- 在web work中进行复杂的计算
- Web work计算结束,通过self.postMessage(msg)给主线程发消息
- 主线程通过workeronmessage=function(msg){}监听消息
- 主线程也可以用同样的方式来给webworker进行通讯
创建 index.html
<html>
<head>
<!-- 引入 manifest 配置 -->
<link rel="manifest" href="manifest.json"></link>
</head>
<body>
<script>
console.log('start')
// 创建一个 web worker
const worker = new Worker('work.js')
worker.addEventListener('message',e=>{
console.log(e.data)
})
console.log('end')
</script>
</body>
</html>
创建 work.js
// 注意: web worker 只是一个独立的线程,不能操作 dom 和 bom
// 适合做大量的计算
let total = 0
for(var i=0;i<1000000;i++){
total += i
}
// 发消息给主线程,把结果给他
self.postMessage({result:total})
启动服务,控制台输入: http-server
从控制台结果来看,web worker 是独立于主线程之外的,适合于做大量的计算,且可以和主线程经常沟通
2.4 web worker
2.4.1 基本介绍
- Web Worker 是临时的,每次做的事的结果还不能被持久存下来,如果下次有同样的复杂操作,还得费时间的重新来一遍
- 一旦被install,就永远存在,除非被手动unregister
- 用到的时候可以直接唤醒,不用的时候自动睡眠
- 可编程拦截代理请求和返回,缓存文件,缓存的文件可以被网页进程取到(包括网络离线状态)
- 离线内容开发者可控
- 必须在HTTPS环境下才能工作
- 异步实现,内部大都是通过Promise实现
2.4.2 使用步骤
- 在window.onload中注册service worker,防止与其他资源竞争
- navigator对象中内置了serviceWorker属性
- service worker在老版本的浏览器中不支持,需要进行浏览器兼容if('serviceWorker'innavigator){}
- 注册service worker navigator.serviceWorker.register('./sw.js’),返回一个promise对象
创建 index.html
<html>
<head>
<!-- 引入 manifest 配置 -->
<link rel="manifest" href="manifest.json"></link>
</head>
<body>
<script>
// 需要在网页加载完成的时候,注册service worker
window.addEventListener('load',()=>{
// 兼容性检查
if('serviceWorker' in navigator){
navigator.serviceWorker
.register('./sw.js')
.then(res=>{
console.log(res)
}).catch(err=>{
console.log(err)
})
}
})
</script>
</body>
</html>
创建 ws.js
console.log('loaded')
浏览器输出结果如下:
2.4.3 生命周期
install事件会在service worker注册成功的时候触发,主要用于缓存资源activate事件会在service worker激活的时候触发,主要用于删除旧的资源fetch事件会在发送请求的时候触发,主要用于操作缓存或者读取网络资源- 如果sw.js发生了改变,install事件会重新触发
- activate事件会在install事件后触发,但是如果现在已经存在service worker了,那么就处于等待状态,直到当前service worker终止
- 可以通过self.skipWaiting()方法跳过等待,返回一个promise对象
- 可以通过event.waitUntil()方法扩的参数是一个promise对象,会在promise结束后才会结束当前生命周期函数,防止浏览器在异步操作之前就停止了生命周期
- service worker激活后,会在下一次刷新页面的时候生效,可以通过self.clients.claim()立即获取控制权