serviceWorker 服务器与浏览器之间的代理

特点:
	.本质上充当服务器与浏览器之间的代理服务器(可以拦截全站的请求,并作出相应的动作->由开发者指定的动作)
	.在web worker的基础上增加了离线缓存的能力
	.由事件驱动的,具有生命周期,其生命周期与页面无关(关联页面未关闭时,它也可以退出,没有关联页面,它也可以启动)
	.可以访问cache和indexDB
	.完全异步,同步API(如XHR和localStorage)不能在service work中使用
	.只能为https承载
	.可以被多个页面所共享(同域情况下)
	.不能缓存POST请求

应用场景:
	.跟 Fetch 搭配,可以从浏览器层面拦截请求,做数据 mock;
	.跟 Fetch 和 CacheStorage 搭配,可以做离线应用;
	.跟 Push 和 Notification 搭配,可以做像 Native APP 那样的消息推送

激活流程:
	.在navigator.serviceWorker.register进行注册后
	.用户首次访问service worker控制的网站或页面时,service worker会立刻被下载
	.无论它与现有service worker不同(字节对比),还是第一次在页面或网站遇到service worker,如果下载的文件是新的,安装就会尝试进行
	.安装成功后它会被激活
	.如果现有service worker已启用,新版本会在后台安装,但不会被激活,这个时序称为worker in waiting
	.直到所有已加载的页面不再使用旧的service worker才会激活新的service worker。只要页面不再依赖旧的service worker,新的service worker会被激活(成为active worker)。
		跳过等待:this.skipWaiting(); 
			跳过installing,直接接管老的service worker,触发activate,在self.addEventListener('install')中调用
		手动更新客户端:self.clients.claim(),
			在self.addEventListener('activate')中清除完旧缓存后调用
	.之后,在以下情况将会触发更新:
		.一个前往作用域内页面的导航
		.在 service worker 上的一个事件被触发并且过去 24 小时没有被下载
	

基本使用:
	Service Worker 注册的代码是放在 HTML 的最后,如果页面加载时没有Service Worker,那么它所依赖的其他资源请求也不会触发 fetch 事件。
	
	1、注册service worker
		.如果注册成功,service worker就会被下载到客户端并尝试安装或激活,这将作用于整个域内用户可访问的URL,或者其特定子集
		
		navigator.serviceWorker.register(url,options)
			url:service worker文件的路径,路径是相对于 Origin ,而不是当前文件的目录的
			optionts
				scope:表示定义service worker注册范围的URL ;service worker可以控制的URL范围。通常是相对URL。默认值是基于当前的location(./),并以此来解析传入的路径.
				假设你的sw文件放在根目录下位于/sw/sw.js路径的话,那么你的sw就只能监听/sw/*下面的请求,如果想要监听所有请求有两个办法,一个是将sw.js放在根目录下,或者是在注册是时候设置scope。
				如设置为/app/即app地址路径下的所有页面如/app/index.html;/app/main/index.html。`
		
		避免第一次打开页面就进行缓存,占用主线程的带宽,以及加剧对cpu和内存的使用
			if ('serviceWorker' in navigator) {
			  window.addEventListener('load', function() {
			    navigator.serviceWorker.register('/sw.js');
			  });
			}

		
		if ('serviceWorker' in window.navigator) {
			navigator.serviceWorker.register('./sw.js', { scope: './' })
			.then(function (res) {
				res:ServiceWorkerRegistration实例
			})
			.catch(function (err) {
			  console.log('fail', err);
			});
			
			注册多个service worker,但scope必须是不同的
			  navigator.serviceWorker.register('./sw/sw.js', { scope: './sw' })
			    .then(function (reg) {
			      console.log('success', reg);
			    })
			  navigator.serviceWorker.register('./sw2/sw2.js', { scope: './sw2' })
			    .then(function (reg) {
			      console.log('success', reg);
			    })
		}
	
	1.5、方法
		主线程中:
			(1)发送信息
				if ('serviceWorker' in window.navigator) {
				  navigator.serviceWorker.register('./sw.js', { scope: './' })
				    .then(function (reg) {
				     方式一:
				     	.如果使用的scope不是Origin下使用
				     	.reg.active就是被注册后激活 Serivce Worker 实例
				     	.由于Service Worker的激活是异步的,因此第一次注册 Service Worker 的时候,Service Worker 不会被立刻激活, reg.active 为 null
				     	
				     	reg.active.postMessage("this message is from page, to sw");
				     	
				     方式二:
				     	确定当前serviceWorker已经激活安装完成
				     	navigator.serviceWorker.controller && navigator.serviceWorker.controller.postMessage("this message is from page");
				     
				     方式三:通过messageChannel
				     
				    });
				    
				    方式四:
			    	  navigator.serviceWorker.register('service-worker.js');
					
					  navigator.serviceWorker.ready.then( registration => {
					    registration.active.postMessage("Hi service worker");
					  });
					 
					 	
			
			(2)销毁service worker
				if ('serviceWorker' in navigator) {
					//获取所有注册的service worker
			       navigator.serviceWorker.getRegistrations()
			           .then(function(registrations) {
							for(let registration of registrations) {
			                     //安装在网页的service worker不止一个,找到我们的那个并删除
			                    if(registration && registration.scope === 'https://seed.futunn.com/'){
			                        registration.unregister(); //进行销毁
			                    }
			                }
			            });
			    }
			 
			 (3)更新service worker
				var version = '1.0.1'
				navigator.serviceWorker.register('/sw.js')
			    .then((reg) => {
			        if(localStorage.getItem('sw_version') !== version) {
			            reg.update()
			                .then(() => {
			                    localStorage.setItem('sw_version', version)
			                })
			        }
			    })
						
				
		在service worker脚本文件中:
			(1)发送消息
				this.addEventListener('message', function (event) {
				  必须使用event.source进行发送,在其他能获取到的函数中也可以
				  event.source.postMessage('this message is from sw.js, to page');
				});
				
				方式二:
					.通过窗口发送,即注册了该serviceWoker的页面的clients对象(即windows对象)
					.client必须要接收到页面发送到serviceWorker的消息后才能发送消息
					
					this.clients.matchAll().then(client => {
					  client[0].postMessage('this message is from sw.js, to page');
					})
				
				方式三:
					通过messageChannel
	
	2、监听
	
		在service worker脚本文件中
			(1)监听被下载安装
				this.addEventListener('install', function (event) {
				  console.log('Service Worker install');
				});
				
				var CACHE_VERSION = 1;
				var CURRENT_CACHES = {
				  prefetch: 'prefetch-cache-v' + CACHE_VERSION
				};
				
				self.addEventListener('install', function(event) {
				  var urlsToPrefetch = [
				    './static/pre_fetched.txt',
				    './static/pre_fetched.html',
				    'https://www.chromium.org/_/rsrc/1302286216006/config/customLogo.gif'
				  ];
									
				  event.waitUntil(
				    caches.open(CURRENT_CACHES['prefetch']).then(function(cache) {
				      cache.addAll(urlsToPrefetch.map(function(urlToPrefetch) {
				        return new Request(urlToPrefetch, {mode: 'no-cors'});
				      })).then(function() {
				        console.log('All resources have been fetched and cached.');
				      });
				    }).catch(function(error) {
				      console.error('Pre-fetching failed:', error);
				    })
				  );
				});
				
			(2)监听被激活
				.触发时可以清理旧缓存和旧的service worker关联的东西
				this.addEventListener('activate', function (event) {
				  console.log('Service Worker activate');
				});
			
			(3)监听信息发送
				this.addEventListener('message', function (event) {
				  console.log(event.data); 
				});
			
			(4)监听浏览器请求
				this.addEventListener('fetch', function (event) {
					...
				}
	
		主线程监听
			(1)监听消息发送
				navigator.serviceWorker.addEventListener('message', function (e) {
				  console.log(e.data); 
				});
			
			(2)监听service worker是否改变
				navigator.serviceWorker.addEventListener('controllerchange', () => {
				  window.location.reload();
				})
	
	3、记录service worker的生命周期
		if ('serviceWorker' in navigator) {
		    $('#isSupport').text('支持');
		
		    // 开始注册service workers
		    navigator.serviceWorker.register('./sw-demo-cache.js', {
		        scope: './'
		    }).then(function (registration) {
		        $('#isSuccess').text('注册成功');
		
		        var serviceWorker;
		        if (registration.installing) {
		            serviceWorker = registration.installing;
		            $('#state').text('installing');
		        } else if (registration.waiting) {
		            serviceWorker = registration.waiting;
		            $('#state').text('waiting');
		        } else if (registration.active) {
		            serviceWorker = registration.active;
		            $('#state').text('active');
		        }
		        if (serviceWorker) {
		            $('#swState').text(serviceWorker.state);
		            serviceWorker.addEventListener('statechange', function (e) {
		                $('#swState').append(' 状态变化为' + e.target.state);
		            });
		        }
		    }).catch (function (error) {
		        $('#isSuccess').text('注册没有成功');
		    });
		} else {
		    $('#isSupport').text('不支持');
		}
		</script>
	
	4、离线背景同步
		.可以先将网络相关任务延迟到用户有网络的时候再执行
		.可以用于保证任何用户在离线的时候所产生对于网络有依赖的操作,最终可以在网络再次可用的时候抵达它们的目标。
		.离线期间所有相同事件只会触发一次,如果希望每一次点击都能触发 sync 事件,就需要在注册的时候赋予它们不同的tag。
		
		navigator.serviceWorker.ready  
		  .then(registration => {
		    document.getElementById('submit').addEventListener('click', () => {
		      背景同步操作
		      registration.sync.register('submit').then(() => {
		        console.log('sync registered!');
		      });
		    });
		  });
		
		service worker中:  
		self.addEventListener('sync', event => {  
		  if (event.tag === 'submit') {
		    console.log('sync!');
		  }
		});
	
	5、最佳实践
		为了保证离线缓存的资源和真实资源一致,优先使用在线资源(即http请求),sw充当本地和线上服务器的代理服务器角色;当在线资源获取出错(服务器宕机,网络不可用等情况),则使用sw本地缓存
		
		优先从线上获取,获取之后设置缓存,以便下一次获取html出错时候再从本地缓存获取的是上一次获取的文件


请求拦截:
	this.addEventListener('fetch', function (event) {
		if(event.request.method === 'POST') {
		      event.respondWith(
		        new Promise(resolve => {
		          event.request.json().then(body => {
		            console.log(body); // 用户请求携带的内容
		          })
		          resolve(new Response({ a: 2 })); // 返回的响应
		        })
		      )
		    }
		}
	}

	self.addEventListener('fetch', function(event) {		
	  event.respondWith(
	    caches.match(event.request).then(function(response) {
	      if (response) {
	        return response;
	      }
	
	      return fetch(event.request).then(function(response) {
	        return response;
	      }).catch(function(error) {
	        throw error;
	      });
	    })
	  );
	});
					
页面缓存:通过Cache Stroage或indexDB进行存储
	因为oninstall和onactivate完成前需要一些时间,service worker标准提供一个waitUntil方法,当oninstall或者onactivate触发时被调用,接受一个promise
	
	event.waitUntil
		.只能在 Service Worker 的 install 或者 activate 事件中使用;
		.如果传递了一个 Promise 给它,那么只有当该 Promise resolved 时,Service Worker 才会完成 install;
		.如果 Promise rejected 掉,那么整个 Service Worker 便会被废弃掉。因此,cache.addAll 里面,只要有一个资源获取失败,整个 Service Worker 便会失效。
	
	event.respondWith
		.只能在 Service Worker 的 fetch 事件中使用;
		.返回一个Promise,当传入的 Promise resolved 之后,才会将对应的 response 返回给浏览器。
		.resolve的内容为 Response对象、a network error
	
	(1)静态资源化缓存
		this.addEventListener('install', function (event) {
		  event.waitUntil(
		    caches.open('sw_demo').then(function (cache) {
		      return cache.addAll([
		        '/style.css',
		        '/panda.jpg',
		        './main.js'
		      ])
		    }
		    ));
		});
	
	(2)动态资源缓存
		this.addEventListener('fetch', function (event) {
		  event.respondWith(
		    caches.match(event.request).then(res => {
		      return res ||
		        fetch(event.request)  获取真实资源并缓存
		          .then(responese => {
		            需要克隆一份,因为请求和响应流只能被读取一次,为了给浏览器返回响应并且还要把它缓存起来,我们不得不克隆一份
		            const responeseClone = responese.clone();
		            caches.open('sw_demo').then(cache => {
		              cache.put(event.request, responeseClone);
		            })
		            return responese;
		          })
		          .catch(err => {
		            console.log(err);
		          });
		    })
		  )
		});

代码示例:
资源加载错误,导航错误页

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request).then(function(response) {
      return response || fetch(event.request);
    }).catch(function() {
      return caches.match('/error.html');
    })
  );
});

错误降级、清除worker

  window.addEventListener('load', function() {
    const sw = window.navigator.serviceWorker
    const killSW = window.killSW || false
    if (!sw) {
        return
    }

    if (!!killSW) {
        sw.getRegistration('/serviceWorker').then(registration => {
            // 手动注销
            registration.unregister();
            // 清除缓存
            window.caches && caches.keys && caches.keys().then(function(keys) {
                keys.forEach(function(key) {
                 caches.delete(key);
                });
            });
        })
    } else {
        // 表示该 sw 监听的是根域名下的请求
        sw.register('/serviceWorker.js',{scope: '/'}).then(registration => {
            // 注册成功后会进入回调
            console.log('Registered events at scope: ', registration.scope);
        }).catch(err => {
            console.error(err)
        })
    }
  });

更新、清除缓存

// sw.js 更换缓存命名空间
this.addEventListener('install', function (event) {
    console.log('install');
    event.waitUntil(caches.open('sw_demo_v2').then(function (cache) { 
        // 更换缓存命名空间
        return cache.addAll(['/style.css','/panda.jpg','./main.js'])
    }))
});

//新的命名空间
const cacheNames = ['sw_demo_v2'];

// sw.js 校验过期的缓存进行清除
this.addEventListener('activate', function (event) {
    event.waitUntil(caches.keys().then(keys => {
        return Promise.all[keys.map(key => {
            if (!cacheNames.includes(key)) {
                console.log(key);
                return caches.delete(key); // 删除不在白名单中的其他命名空间的 Cache Stroage
            }
        })]
   }))
});

雨雀官网的缓存

self.assets = ["https://gw.alipayobjects.com/os/chair-script/skylark/common.b4c03be5.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/common.e2d71ce8.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__components__Explore__Recommend~p__explore__routers__Docs~p__explore__routers__Repos~p_~d6257766.aa1bcc43.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__components__Explore__Recommend~p__explore__routers__Docs~p__explore__routers__Repos~p_~d6257766.fac19d5b.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/c__Lakex~p__editor__routers__TextEditor.9defba11.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/c__Lakex~p__editor__routers__TextEditor.3a98afb8.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__bookRepo__routers.244d87f7.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__bookRepo__routers.ef3c862f.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/c__Lakex.acd5cec4.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/c__Lakex.653d1e93.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/layout__MainLayout.ae548301.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/layout__MainLayout.c0075e36.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__bookRepo__model.511a24e3.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__bookRepo__routers__EditCustomIndex.d4fbfe9e.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__bookRepo__routers__EditCustomIndex.28048163.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__bookRepo__routers__ShareExpired.8113c1a2.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__bookRepo__routers__ShareExpired.b6dff962.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__bookRepo__routers__SharePassword.1a6ae926.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__bookRepo__routers__SharePassword.f76c7685.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__components__Explore__Events.6d43e196.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__components__Explore__Events.979d04c6.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__components__Explore__Recommend.ab8c57cb.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__components__Explore__Recommend.ac025d9d.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__model.2d27d4bc.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__routers__App.4d4a0a8c.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__routers__App.08fcac15.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__routers__CollabBooks.40627926.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__routers__CollabBooks.91d8d56d.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__routers__Collects.0a516ca7.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__routers__Collects.b5f172fe.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__routers__Dashboard.5f89b7f3.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__routers__Dashboard.be7c1714.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__routers__Explore.b51bb073.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__routers__Groups.198f522b.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__routers__Groups.ad67b3b7.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__routers__History.086ddd9c.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__routers__History.5387e7a8.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__routers__MyBooks.40627926.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__routers__MyBooks.61608f6e.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__routers__Notes.a878e2d7.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__routers__Notes.ffe2cc7a.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__routers__Recycles.ab448ca1.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__dashboard__routers__Recycles.3434b09c.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__doc__model__page.424fcfd2.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__doc__routers.66f72a35.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__doc__routers.39267068.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__doc__routers__version.e7b71a05.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__doc__routers__version.186ff53b.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__editor__model.7ef254a2.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__editor__routers__Asl.60282b53.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__editor__routers__Asl.fa585dad.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__editor__routers__TextEditor.f413dbfc.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__editor__routers__TextEditor.81c5d11d.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__editor__routers__board.591d841b.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__editor__routers__board.832f1003.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__editor__routers__doc.a1ccd84d.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__editor__routers__doc.e652cf65.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__editor__routers__embed.500645af.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__editor__routers__embed.743631c5.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__editor__routers__embed_extreme.5563bfd4.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__editor__routers__embed_extreme.88434cbe.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__editor__routers__sheet.8a86af45.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__editor__routers__sheet.2daf2fb0.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__editor__routers__show.75463f8e.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__editor__routers__show.14157f9c.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__editor__routers__table.60aad9c2.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__editor__routers__table.29a799ed.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__group__model.263db0b2.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__group__routers__Books.cfc93cd2.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__group__routers__Books.8ffd07d8.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__group__routers__Custom.710dc957.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__group__routers__Custom.604bf4aa.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__group__routers__Embed.daf129f3.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__group__routers__Embed.1a8cd333.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__group__routers__Error403.8113c1a2.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__group__routers__Error403.e426da8e.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__group__routers__Group.a1fbd1b1.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__group__routers__Group.aca6ba40.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__group__routers__Members.c73713ca.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__group__routers__Members.fc9d4e92.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__group__routers__Migrate.e821f2d6.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__group__routers__Migrate.c5718315.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__group__routers__Recycles.724821a4.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__group__routers__Recycles.9b99a94d.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__group__routers__Statistics.e849f2e3.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__group__routers__Statistics.e2b4dc68.async.js", "https://gw.alipayobjects.com/os/chair-script/skylark/p__group__routers__Upgrade.a42075c1.chunk.css", "https://gw.alipayobjects.com/os/chair-script/skylark/p__group__routers__Upgrade.d80c9df1.async.js", "https://gw.alipayobjects.com/os/lib/??react/16.13.1/umd/react.production.min.js,react-dom/16.13.1/umd/react-dom.production.min.js,react-dom/16.13.1/umd/react-dom-server.browser.production.min.js,moment/2.24.0/min/moment.min.js", "https://gw.alipayobjects.com/as/g/larkgroup/lake-codemirror/6.0.2/CodeMirror.js", "https://gw.alipayobjects.com/as/g/larkgroup/lark-sheet/11.0.20/lark-sheet.css", "https://gw.alipayobjects.com/a/g/lark/??immutable/3.8.2/immutable.min.js", "https://gw.alipayobjects.com/as/g/larkgroup/lark-sheet/11.0.20/lark-sheet.js"];
self.resourceBase = "https://gw.alipayobjects.com/os/chair-script/skylark/";

self.addEventListener("install", (e => {
  	//预加载常用资源
    Array.isArray(self.assets) && e.waitUntil(caches.open("v1").then((e => {
      e.addAll(self.assets)
    })))
})), self.addEventListener("activate", (e => {
  Array.isArray(self.assets) && caches.open("v1").then((e => {
    e.keys().then((t => {
      t.forEach((t => {
        //过期资源释放
        self.assets.includes(t.url) || e.delete(t)
      }))
    }))
  }))
}));
const r = [self.resourceBase, "https://at.alicdn.com/t/", "https://gw.alipayobjects.com/os/"];
self.addEventListener("fetch", (e => {
  //拦截资源,满足上述域名,优先使用缓存,否则使用网络下载资源并更新资源。
  r.some((t => e.request.url.startsWith(t))) && e.respondWith(caches.match(e.request).then((t => t && 200 === t.status ? t : fetch(e.request).then((t => {
    if (200 !== t.status) return t;
    const r = t.clone();
    return caches.open("v1").then((t => {
      t.put(e.request, r)
    })), t
  })).catch((() => {})))))
}))

缓存、缓存更新、拦截请求

// 缓存静态资源文件列表
let cacheFiles = [
  './test.js',
  './index.html',
  './src/img/yy.png'
]
// serviceworker使用版本
let __version__ = 'cache-v2'

// 缓存静态资源
self.addEventListener('install', function (evt) {
  // 强制更新sw.js
  self.skipWaiting()
  evt.waitUntil(
    caches.open(version).then(function (cache) {
      return cache.addAll(cacheFiles)
    })
  )
})

// 缓存更新
self.addEventListener('active', function (evt) {
  evt.waitUntil(
    caches.keys().then(function (cacheNames) {
      return Promise.all(
        cacheNames.map(function (cacheName) {
          if (cacheName !== version) {
            return caches.delete(cacheName)
          }
        })
      )
    })
  )
})

// 请求拦截
self.addEventListener('fetch', function (evt) {
  console.log('处理fetch事件:', evt.request.url)
  evt.respondWith(
    caches.match(evt.request).then(function (response) {
      if (response) {
        console.log('缓存匹配到res:', response)
        return response
      }
      console.log('缓存未匹配对应request,准备从network获取', caches)
      return fetch(evt.request).then(function (response) {
        console.log('fetch获取到的response:', response)
        // 必须是有效请求,必须是同源响应,第三方的请求,因为不可控,最好不要缓存
        if (!response || response.status !== 200 || response.type !== 'basic') {
	        caches.open(version).then(function (cache) {
	          cache.put(evt.request, response)
	        })
        }
        return response;

      })
    }).catch(function (err) {
      console.error('fetch 接口错误', err)
      throw err
    })
  )
})


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值