pwa缓存

pwa必须满足的三大要素:
  • https或者http://localhost
  • manifest
  • service worker
缓存类别
  • 用户代理缓存(浏览器缓存)
  • manifest

<html lang='en' manifest="./deafult.cache">
	<head>
		<meta charset="utf-8" />
		<title>title>
	head>
	<body>
		<img src="img/1.jpg" />
		<img src="img/2.jpg" />
		<img src="img/3.jpg" />
	body>
html>
  • deafult.cache
CACHE MANIFEST
CACHE:
#此标题下,将在第一次下载后缓存
img/1.jpg
img/2.jpg
img/3.jpg
404.html

NETWORK:
#此列表下文件需要与服务器关联
/login.html

FALLBACK
# 下面标题下文件,当页面无法访问,跳转
./ 404.html
  • sessionStorage
  • localStorage
  • cookie
  • indexDB
  • CacheStorage
mainfest
  • Manifest.json文件是5+移动App的配置文件,用于指定应用的显示名称、图标、应用入口文件地址及需要使用的设备权限等信息。是扩展的配置文件,指明了扩展的各种信息。
  • 参考 https://developer.mozilla.org/zh-CN/docs/web/manifest
  • Manifest Validator 清单文件验证工具:https://manifest-validator.appspot.com/
  • html
<link rel="manifest" href="./manifest.json" />
Web Worker

Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。这样的好处是,一些计算密集型或高延迟的任务,被 Worker 线程负担了,主线程(通常负责 UI 交互)就会很流畅,不会被阻塞或拖慢。

Worker 线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。但是,这也造成了 Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。

Web Worker 有以下几个使用注意点:

(1)同源限制
分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。

(2)DOM 限制
Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用document、window、parent这些对象。但是,Worker 线程可以navigator对象和location对象。

(3)通信联系
Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过消息完成。

(4)脚本限制
Worker 线程不能执行alert()方法和confirm()方法,但可以使用 XMLHttpRequest 对象发出 AJAX 请求。

(5)文件限制
Worker 线程无法读取本地文件,即不能打开本机的文件系统(file://),它所加载的脚本,必须来自网络。

  • index.html

<html>
	<head>
		<meta charset="UTF-8">
		<title>title>
	head>
	<body>
		<script>
			if(typeof(Worker)=='undefined'){
				alert('浏览器不支持Worker')
			}
			else{
				var a=new Worker('./Worker.js');
				a.postMessage('start');
				a.onmessage=function(e){
					if(e.data>20){
						a.terminate();//子进程注销
					}
					else{
						console.log(e.data)
					}
				}
			}
		script>
		
	body>
html>
  • Worker.js
self.addEventListener('message',(e)=>{
	let i=0;
	setInterval(function(){
		i++;
		self.postMessage(i)
	},1000)
})
cacheStorage

用于缓存文件

caches.delete('config'); //删除(相当于初始化)
var aaa=new Promise((resolve,reject)=>{
	caches.open('config').then(cache=>{
	    //version相当于数据库名
		resolve(cache.put('/version',new Response('1.0.0',{status:200})))					
	})
})
aaa.then(function(){
	return caches.match('/version')
}).then(function(r){
	return r.text()
}).then(function(r){
	console.log(r) //1.0.0
})
service workers

终止情况:

  • 有任何的资源文件请求不到,都会导致serviceWorker进程退出
  • serviceWorker安装或者激活失败
  • serviceWorker功能事件完成,处于空闲状态
  • serviceWorker执行时间过长,线程会自动退出,比如serviceWorker执行时间超过30秒,或者fetch超过5分钟还未完成

流程:
pwa缓存_第1张图片

离线应用
  • html

<html>
	<head>
		<meta charset="UTF-8">
		<title>title>
		<link rel="manifest" href="webmanifest.json">
	head>
	<body>
		<img src="../assets/touch/homescreen144.png" />
	body>
	<script>
		if('serviceWorker' in navigator) {
		    navigator.serviceWorker.register('./sw.js');
		};
	script>
html>
  • sw.js
var cacheName = 'sw-v1';
var appShellFiles = [
  './',
  './index.html',
  './sw.js',
  './assets/style/index.css',
  './assets/touch/homescreen96.png',
  './assets/touch/homescreen48.png',
  './assets/touch/homescreen72.png',
  './assets/touch/homescreen144.png',
  './assets/touch/homescreen168.png',
  './assets/touch/homescreen192.png',
];

self.addEventListener('install', function(e) {
    console.log('[Service Worker] Install');
    e.waitUntil(
    caches.open(cacheName).then(function(cache) {
      console.log('[Service Worker] Caching all: app shell and content');
      return cache.addAll(appShellFiles);
    })
  );
});

self.addEventListener('fetch', function(e) {
  e.respondWith(
    caches.match(e.request).then(function(r) {
      console.log('[Service Worker] Fetching resource: '+e.request.url);
      return r || fetch(e.request).then(function(response) {
          return caches.open(cacheName).then(function(cache) {
          console.log('[Service Worker] Caching new resource: '+e.request.url);
          cache.put(e.request, response.clone());
          return response;
        });
      });
    })
  );
});

self.addEventListener('activate', function(e) {
  e.waitUntil(
    caches.keys().then(function(keyList) {
      return Promise.all(keyList.map(function(key) {
        if(cacheName.indexOf(key) === -1) {
          return caches.delete(key);
        }
      }));
    })
  );
});
  • webmanifest.json
{
    "name": "HelloPWADEMO",
    "short_name": "PWADEMO",
    "start_url": ".",
    "display": "fullscreen",
    "background_color": "#000000",
    "description": "A simply Manifest.",
    "icons": [{
      "src": "assets/touch/homescreen48.png",
      "sizes": "48x48",
      "type": "image/png"
    }, {
      "src": "assets/touch/homescreen72.png",
      "sizes": "72x72",
      "type": "image/png"
    }, {
      "src": "assets/touch/homescreen96.png",
      "sizes": "96x96",
      "type": "image/png"
    }, {
      "src": "assets/touch/homescreen144.png",
      "sizes": "144x144",
      "type": "image/png"
    }, {
      "src": "assets/touch/homescreen168.png",
      "sizes": "168x168",
      "type": "image/png"
    }, {
      "src": "assets/touch/homescreen192.png",
      "sizes": "192x192",
      "type": "image/png"
    }],
    "related_applications": [{
      "platform": "web"
    }]
  }
  • name:web app的全名

  • short_name:在主界面显示的名字

  • description:app的简单描述

  • icons:icon的信息——资源的URL,大小,种类。请确保多添加一个不同尺寸的icon,这样就可以在用户的设备上显示最合适的一个。

  • start_url:启动应用的入口文件

  • display:app怎么显示:全屏,standalone(隐藏浏览器UI),minimal-ui(和standalone类似,不过浏览器会显示一些最基本的导航UI,浏览器不同显示内容可能不同),browser(原始样式)。

  • theme_color:操作系统使用的UI主色调。

  • background_color:背景色,安装和初始屏幕时使用。

  • 最最基本的信息是name和至少一个的icon(包括src,size和type)。推荐添加description,short_name和start_url。除了上述的参数之外,还有其他的一些参数——请查看Web App Manifest reference。

安装
//index.html

<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <link rel="manifest" href="manifest.json">
  <link rel="stylesheet" href="./assets/style/index.css">
  <link rel="apple-touch-icon" href="./assets//touch/homescreen144.png"/>
  <title>THIS TITLEtitle>
head>
<body>
<div class="logo">
  <button id="btn">点击button>
  <img src="./assets/images/logo.png" alt="" id="logo">
div>
<div id="tip">div>
body>
<script>

  tip("脚本启动1")
  if ('serviceWorker' in navigator) {
    if (navigator.serviceWorker.controller === null){ //判断是否注册过serviceWorker
      window.addEventListener('load', function() { //页面加载完成后注册服务
        navigator.serviceWorker.register('./serviceWorker.js').then(function(registration) {
          tip('注册成功')
        }).catch(function(err) {
          tip('注册失败')
        });
      });
    }
  }else{
    tip("浏览器不支持serviceWorkers... ")
  }

  if(window.fetch){
    fetch("./fetch.json")
      .then(function(resolve){
        resolve.json().then(function(data) {
          //console.log(data)
        })
      })
      .catch(function(reject){
        //console.log(reject)
      })
  }

  document.getElementById('logo').addEventListener('click', function () {
    navigator.serviceWorker.controller && navigator.serviceWorker.controller.postMessage('Hello PWA')
  })
  navigator.serviceWorker.addEventListener('message', function (e) {
    tip(e.data)
  });
  var dfdPrompt = null;
  var button = document.getElementById('btn');

  window.addEventListener('beforeinstallprompt', function (e) {
    console.log(e)
    // 存储事件
    dfdPrompt = e;
    // 显示按钮
    button.style.display = 'block';
    // 阻止默认事件
    e.preventDefault();
    return false;
  });

  button.addEventListener('click', function (e) {
    console.log(dfdPrompt)
    if (dfdPrompt == null) {
      return;
    }
    // 通过按钮点击事件触发横幅显示
    dfdPrompt.prompt();
    // 监控用户的安装行为
    dfdPrompt.userChoice.then(function (choiceResult) {
      alert(choiceResult.outcome);
    });
    // 隐藏按钮
    button.style.display = 'none';
    dfdPrompt = null;
  });

  //下部提示信息
  function tip(alertStr){
    document.getElementById("tip").innerHTML=alertStr
  }
script>
html>
//serviceWorker.js
var CACHE_NAME = 'vesion201'
var urlToCache = [
  '/index.html',
  './assets/images/logo.png',
  './assets/style/index.css',
  './fetch.json'
]

self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(function(cache) {
        return cache.addAll(urlToCache)
      })
      .catch(function(err){
        console.log("err: " + err)
      })
  )
  sendMessage('installed')
})
self.addEventListener('activate', function(event) {
  sendMessage("activate")
})

self.addEventListener('message', function (event) {
  sendMessage(event.data);
});


function sendMessage(str){
  self.clients.matchAll()
    .then(function (clients) {
      if (clients.length>0) {
        clients.forEach(function (client) {
          client.postMessage(str);
        })
      }
    })
}

/*self.addEventListener('fetch', function(event) {
  console.log("fetch")
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
          if (response) {
            return response
          }
          return fetch(event.request)
        }
      )
  )
})*/

self.addEventListener('fetch', function(e) {
  e.respondWith(
    caches.match(e.request).then(function(r) {
      console.log('[Service Worker] Fetching resource: '+e.request.url);
      return r || fetch(e.request).then(function(response) {
          return caches.open(cacheName).then(function(cache) {
          console.log('[Service Worker] Caching new resource: '+e.request.url);
          cache.put(e.request, response.clone());
          return response;
        });
      });
    })
  );
});

self.addEventListener('notificationclick', function(event) {
  sendMessage("关闭了消息");
});
//fetch.json
{
  "a":"1",
  "b":"2"
}
//manifest.json
{
  "name": "HelloPWADEMO",
  "short_name": "PWADEMO",
  "start_url": ".",
  "display": "fullscreen",
  "background_color": "#000000",
  "description": "A simply Manifest.",
  "icons": [{
    "src": "assets/touch/homescreen48.png",
    "sizes": "48x48",
    "type": "image/png"
  }, {
    "src": "assets/touch/homescreen72.png",
    "sizes": "72x72",
    "type": "image/png"
  }, {
    "src": "assets/touch/homescreen96.png",
    "sizes": "96x96",
    "type": "image/png"
  }, {
    "src": "assets/touch/homescreen144.png",
    "sizes": "144x144",
    "type": "image/png"
  }, {
    "src": "assets/touch/homescreen168.png",
    "sizes": "168x168",
    "type": "image/png"
  }, {
    "src": "assets/touch/homescreen192.png",
    "sizes": "192x192",
    "type": "image/png"
  }],
  "related_applications": [{
    "platform": "web"
  }]
}

说明
  • service worker会在waitUntil内的代码全部执行完才进行安装。其返回了一个promise——这是必要的,因为通常安装需要花费一些时间,所以我们需要稍作等待才行。
  • caches是一个特殊的CacheStorage对象,我们通过一个cache名打开了一个缓存,并将所有应用将用到的文件都添加进了缓存,这样下次加载时这些缓存就可以派上用场了(由request URL来识别)。
  • 我们还需要处理一个叫做fetch的事件,每当有HTTP请求到来时就会被触发。这非常有用,因为它允许我们打断请求,并用自定义的响应来回复。
self.addEventListener('fetch', function(e) {
    console.log('[Service Worker] Fetched resource '+e.request.url);
});
  • 对于一个fetch事件,如果在缓存中有对应的资源则直接返回其内容。否则,我们向服务器发起请求,并将得到的响应存入缓存中,这样下次有请求时缓存就可以派上用场了。
    FetchEvent.respondWith方法获取了控制权——这相当于创建了一个应用和网络之间的代理服务器。对于每一个请求,我们都可以返回任何我们希望的值:由Service Worker准备,从缓存中取得,必要时进行修改。
消息推送

https://www.jianshu.com/p/abf254f89e36

你可能感兴趣的:(前端)