美文网首页
JS PWA相关技术

JS PWA相关技术

作者: 风之化身呀 | 来源:发表于2019-02-26 18:38 被阅读0次

PWA 全称是渐进式 web 应用,它是用一系列前端技术来实现的,目标是提供类似原生APP一样的体验。主要解决的痛点是:

  • 网页离线无法访问
  • 缓存不可编程,即不能通过 js 控制缓存的增删改查,只能通过修改资源的hash之类的方式让缓存失效
  • 没有桌面入口,只能通过浏览器打开
  • 无消息推送功能

以下介绍 PWA 相关技术

1、Service Worker

PWA中最重要的一项技术,特点是:

  • 单独起线程,不影响主JS线程
  • 是个浏览器后台线程,由于脱离了浏览器窗体,故无法访问DOM和window
  • 设计为全异步,故不能使用 XHR 和 localStorage 等
  • 必须使用https协议(开发环境除外)
  • 桌面端Chrome、Firefox、Safari可用,IE不可用,Edge可用;移动端safari>=11.4可用;android>=67可用
  • sw.js 有路径的概念,所以一般放在项目根目录,方便管理所有的页面;‘/path/sw.js’只能管理path路径下的页面
navigator.serviceWorker.register('/sw.js', { scope: '/js' }) // 第二个参数制定 sw.js 管理的范围
  • 可使用 postMessage实现sw.js 和主 JS 进程双向通信
    1、sw.js => 主js,借用了 clients 全局对象,每个client 代表一个 tab 窗口
// sw.js
const allClients = await clients.matchAll();
allClients.forEach(client => client.postMessage(msg));
// 主 js
if("serviceWorker" in navigator) {
    navigator.serviceWorker.addEventListener("message", function(event) {
        let msg = event.data;
        console.log('message',msg)
    }); 
}

2、主 js => sw.js

// 主 js
navigator.serviceWorker.controller.postMessage({
    type: 1, 
    desc: "remove html cache", 
    url: window.location.href}
);
// sw.js
this.addEventListener("message", function(event) {
    let msg = event.data;
    console.log(msg);
});
  • 缓存空间很大,不用担心不够用

  • 事件
    install 安装后,activate 激活后,fetch 代理请求。sync 恢复网络时做些事情
    install 用来缓存文件,activate 用来缓存更新,fetch用来拦截请求直接返回缓存数据。三者齐心,构成了完成的缓存控制结构。sync 事件可以知道什么时候恢复了网络

  • 一个demo

// 主 js 注册 serviceWorker
if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('./sw-demo-cache.js');
}

// sw-demo-cache.js
var VERSION = 'v1';
// 开始缓存
self.addEventListener('install', function(event) {
  this.skipWaiting();  // 避免更新后的 service-worker 处于等待状态
  event.waitUntil(
    caches.open(VERSION).then(function(cache) {
      return cache.addAll([
        './start.html',
        './static/jquery.min.js',
        './static/mm1.jpg'
      ]);
    })
  );
});

// 更新缓存
self.addEventListener('activate', function(event) {
  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          // 如果当前版本和缓存版本不一致
          if (cacheName !== VERSION) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});

// 捕获请求并返回缓存数据
self.addEventListener('fetch', function (event) {
  event.respondWith(
    caches.match(event.request)
      .then(function (resp) {
        if (resp) {
          console.log(new Date(), 'fetch ', event.request.url, '有缓存,从缓存中取')
          return resp
        } else {
          console.log(new Date(), 'fetch ', event.request.url, '没有缓存,网络获取')
          return fetch(event.request)
            .then(function (response) {
              return caches.open(VERSION).then(function (cache) {
                cache.put(event.request, response.clone())
                return response
              })
            })
        }
      })
  )
})


  • 缺点
    一个资源需要更新,就得放弃所有其他不需要更新的资源缓存。所以一般要配合 http 缓存一起使用。当 service-worker 缓存失效时,再走 http 缓存
2、Cache和CacheStorage

caches 缓存库一般以request 为key , response为value

  • 创建 caches 缓存库
caches.open(CACHE_NAME);
  • 添加缓存 put(key,value) or addAll(resourseArray)
// 请求资源并添加到缓存里面去
caches.open(CACHE_NAME).then(cache => {
   cache.addAll(cacheResources);
   // cache.put(request, resource);
})
  • 查看缓存是否存在 match(key)
caches.match(event.request).then(response => {
   // cache hit
   if (response) {
       return response;
   }
})
  • 删除缓存 delete(key)
caches.open(CACHE_NAME).then(cache => {
     console.log("delete cache " + url);
     cache.delete(url, {ignoreVary: true});
 });
3、Web App Manifest添加桌面入口

在项目根目录下准备一个 manifest.json 文件,可以实现用户首次访问网页时提示在桌面创建网页入口icon,以后直接通过桌面的icon就可以直接访问网页了。
注意:只有至少已经访问网站两次、访问至少间隔五分钟时才可以将网络应用添加到主屏幕上。

  "short_name": "人人FED", // 桌面应用的名字
  "name": "人人网FED,专注于前端技术",  // 启动时欢迎语
  "icons": [ // 启动图标
    { 
      "src": "/html/app-manifest/logo_48.png",
      "type": "image/png",
      "sizes": "48x48"
    },
    {
      "src": "/html/app-manifest/logo_96.png",
      "type": "image/png",
      "sizes": "96x96"
    },
    {
      "src": "/html/app-manifest/logo_192.png",
      "type": "image/png",
      "sizes": "192x192"
    },
    {
      "src": "/html/app-manifest/logo_512.png",
      "type": "image/png",
      "sizes": "512x512"
    }
  ],
  "start_url": "/?launcher=true",   // 这个地址要被 service worker 缓存起来
  "display": "standalone", // 启动后隐藏浏览器地址栏
  "background_color": "#287fc5",
  "theme_color": "#fff"
}

然后在 html 文件里引入该文件

    
<link rel="manifest" href="/html/app-manifest/manifest.json">
4、消息提醒与信息推送
  • 消息提醒
    主 js
// 1、ask for permission
Notification.requestPermission(permission => {  
  console.log('permission:', permission);
});

// 2、display notification
displayNotification(msg)
function displayNotification(msg) {  
  if (Notification.permission == 'granted') {
    navigator.serviceWorker.getRegistration()
      .then(registration => {
        registration.showNotification(msg);
      });
  }
}

sw.js

self.addEventListener('notificationclick', event => {  
  // 消息提醒被点击的事件
  event.waitUntil(clients.openWindow('https://baidu.com'))
});

self.addEventListener('notificationclose', event => {  
  // 消息提醒被关闭的事件
});
  • 消息推送
    需要后端配合,比较麻烦,暂时放弃


    消息推送流程
参考

相关文章

网友评论

      本文标题:JS PWA相关技术

      本文链接:https://www.haomeiwen.com/subject/wniayqtx.html