PWA初探整理

关键特性

  • Web App Manifest – 在主屏幕添加app图标,定义手机标题栏颜色之类
  • App Shell – 先显示APP的主结构,再填充主数据,更快显示更好体验
  • Service Worker - 缓存,离线开发,以及地理位置信息处理等
  • Push Notifion - 消息推送

Service Worker

运行在浏览器端的代理服务器

clipboard.png

基本特色

  • 事件驱动型服务线程
  • 只能基于https或者localhost
  • 能够控制页面所发送网络请求的处理方式
  • 运行在浏览器后台的脚本,没法直接操做dom

生命周期

clipboard.png

支持事件

clipboard.png

register

  • 在主线程代码中注册
  • 能够指定scope,一般指定到网站根路径,可以拦截全部的fetch事件
  • service worker 已经被注册过,浏览器会自动忽略上面的代码
if ('serviceWorker' in navigator) {
  window.addEventListener('load', function () {
    navigator.serviceWorker.register('/sw.js', {
      scope: '/'
    }).then(function (reg) {
      // 注册成功
      console.log('success and scope: ', reg.scope);
    }).catch(function (err) {
      // 注册失败
      console.log('failed: ', err);
    });
  });
}

installing

缓存文件

installed/waiting

此状态下,worker有效但还没有激活,它还没有归入 document的控制,确切来讲是在等待着从当前 worker 接手html

sw.js发生了更新,可是页面一直挂载中,没有关闭或强制刷新,此时上一个版本的sw还在工做中,新的sw处于等待中git

// 安装阶段跳过等待,直接进入 active
self.addEventListener('install', function (event) {
  event.waitUntil(self.skipWaiting());
});

self.addEventListener('activate', function (event) {
  event.waitUntil(
    Promise.all([

      // 更新客户端
      self.clients.claim()

    ])
  );
});

activating/activated

缓存更新

fetch

代理请求

message

sw与主线程间的双向通讯,创建MessageChannel做为纽带github

// index.html
navigator.serviceWorker.register('/service-worker.js', {
  scope: '/'
}).then(function (reg) {
  // 建立一个
  const channel = new MessageChannel();
  
  // port1供主线程使用
  channel.port1.onmessage = messageEvent => {
    console.log('来自sw的message', messageEvent.data);
  }
  
  const serviceWorker = reg.active;
  
  // port2指向sw
  if (serviceWorker) {
    serviceWorker.postMessage('index->sw', [channel.port2]);
  }
});

// sw.js
self.addEventListener('message', function (event) {
  console.log('来自index的message', event.data);
  // 经过port找到发送消息的client
  event.ports[0].postMessage('sw->index');
});

更多的应用场景

  • 后台数据同步
  • 预取用户可能须要的资源,好比相册中的后面数张图片
  • 在后台集中接收计算成本高的数据更新,好比地理位置和陀螺仪信息,多个页面就能够利用同一组数据

Cache API

  • 只能缓存 GET 请求;
  • 能够缓存属于本身域下的请求,同时也能够缓存跨域的请求,不过没法对跨域请求的Request和Response进行修改
  • 缓存的更新须要自行实现
  • 缓存不会过时,除非将手动删除,大小有限制,LRU删除

caches.open

建立一个cachejson

cache.add/addAll

  • 支持传入Requesturl
  • 缓存资源,支持单个和数组
  • 在cache.add内部会自动去调用fetch取回request的请求结果,而后才是把response存入cache

cache.put

  • 至关于cache.add的第二步,即fetch到response后存入cache
  • 没法直接缓存跨域的请求,response.status会返回0segmentfault

    • 若是跨域的资源支持CORS,那么能够把request的mod改为cors

caches.match

catch.match(request, {
  
}).then(function(response) {

})

cache.delete

一些使用点

  • 分段缓存,提升安装成功率后端

    • 先安装非重要资源,再安装重要资源
  • 渐进式缓存跨域

    • 对于在install时没有缓存的资源,能够在用户交互以后再缓存
  • 优先原则数组

    • 对于静态页面,缓存优先,减小请求
    • 对于天气类型应用,先去fetch,服务器故障或者网络不良时,折回本地缓存

Manifest

一个基本的manifest.json浏览器

{
    "short_name": "短名称",
    "name": "这是一个完整名称",
    "icon": [
        {
            "src": "icon.png",
            "type": "image/png",
            "sizes": "48x48"
        }
    ],
    "start_url": "index.html"
}

能够实现的功能缓存

  • 基本功能

    • 自定义名称
    • 自定义图标
    • 设置启动网址
    • 设置做用域
  • 添加启动画面

    • 设置显示类型
    • 指定显示方向
    • 设置主题色
  • 应用安装横幅

    • 站点部署 manifest.json,该文件需配置以下属性:

      • short_name (用于主屏幕显示)
      • name (用于安装横幅显示)
      • icons (其中必须包含一个 mime 类型为 image/png 的图标声明)
      • start_url (应用启动地址)
      • display (必须为 standalone 或 fullscreen)
    • 站点注册 Service Worker。
    • 站点支持 HTTPS 访问。
    • 站点在同一浏览器中被访问至少两次,两次访问间隔至少为 5 分钟。

Web Push

Notification

PushManager

clipboard.png

  • 询问受权
  • 发送subscription给后端存储
  • 服务端向FCM/GCM发送消息,同时带上subscription
  • FCM根据subscription再下发给对应的浏览器
  • 触发Service Worker的push事件
  • 后续处理

参考

相关文章
相关标签/搜索