美文网首页
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