JS PWA相关技术

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 => {  
  // 消息提醒被关闭的事件
});
  • 消息推送
    需要后端配合,比较麻烦,暂时放弃


    消息推送流程
参考
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容