Service Worker 基本用法

同喜
• 阅读 4993

看了很多介绍Service Worker的,看得都挺模糊的,所以决定自己写一篇文件整理一下思路。

一、Service Worker API 名词区分

1、ServiceWorkerContainer:navigator.serviceWorker返回的就是Service WorkerContainer对象,主要是用户在页面注册serviceWorker,调用方法:

navigator.serviceWorker.register(scriptURL, options)
    .then(function(ServiceWorkerRegistration) { ... })

2、ServiceWokrerGlobalScope:主要是用户在sw.js文件的全局变量,即this的指向
3、ServiceWorkerRegistration:在页面调用serviceWorker.register注册返回一个Promise对象,当resolve时传递给then的函数参数就是ServiceWorkerRegistration.
4、ServiceWorker:表示ServiceWorkerRegistration.installing || ServiceWorkerRegistration.waiting || ServiceWorkerRegistration.active

二、Service Worker 注意事项

1、建立在HTTPS上;
2、不支持缓存POST请求;

三、Service Worker 注册

1、index.html

<script>
    // register
    if("serviceWorker" in navigator){
        navigator.serviceWorker.register('./sw.js')
            .then(function(registration){
                console.log("Register success: ",registration.scope);
            })
            .catch(function(err){
                console.log("Register failed: ",err);
            });
    }else{
        console.log('Service workers are not supported.');
    }
</script>

2、sw.js

var CACHE_NAME = 'sw-test-v1';
this.addEventListener('install',function(event){
    console.log("installing...");
    event.waitUntil(caches.open(CACHE_NAME).then(function(cache){
        cache.addAll([
            'images/resource01.jpg',
            'images/resource02.jpg',
            ....
        ]);
    }));
});
this.addEventListener('fetch', function(event) {
    event.respondWith(
        caches.match(event.request)
            .then(function(response) {
                if (response) { // 缓存命中,返回缓存
                    return response;
                }
                // 请求是stream数据,只能使用一次,所以需要拷贝,一次用于缓存,一次用于浏览器请求
                var fetchRequest = event.request.clone();
                return fetch(fetchRequest)
                    .then(function(response) {
                        if(!response || response.status !== 200) {
                            return response;
                        }
                        // 响应也是stream,只能使用一次,一次用于缓存,一次用于浏览器响应
                        var responseToCache = response.clone();
                        caches.open(CACHE_NAME)
                            .then(function(cache) {
                                cache.put(event.request, responseToCache);
                            });
                        return response;
                    });
            })
  );
});

sw.js工作内容:首先监听install事件,调用cache.addAll()方法将静态资源加入缓存中。然后监听fetch事件,判断当前请求的url是否在缓存中,如果在则返回内容,如果不在,则向服务端发起请求数据,将返回的数据放入缓存中并且返回给浏览器。
代码中的方法解析:
1、caches.match():检查给定的Request对象或url字符串是否是一个已存储的 Response对象的key. 该方法针对 Response 返回一个 Promise ,如果没有匹配则返回 undefined 。cache对象按创建顺序查询,等同于在每个缓存上调用 cache.match() 方法 (按照caches.keys()返回的顺序) 直到返回Response 对象。语法如下:

caches.match(request, options).then(function(response) {
  // Do something with the response
});

参数解析:

options: 可选,配置对象中的属性控制在匹配操作中如何进行匹配选择,具体属性如下:

  • ignoreSearch: Boolean值, 指定匹配过程是否应该忽略url中查询参数,默认 false。
  • ignoreMethod: Boolean 值,当被设置为 true 时,将会阻止在匹配操作中对 Request请求的 http 方式的验证 (通常只允许 GET 和 HEAD 两种请求方式)。该参数默认为 false.
  • ignoreVary: Boolean 值,当该字段被设置为 true, 告知在匹配操作中忽略对VARY头信息的匹配。换句话说,当请求 URL 匹配上,你将获取匹配的 Response 对象,无论请求的 VARY 头存在或者没有。该参数默认为 false.
  • cacheName: DOMString 值, 表示所要搜索的缓存名称。

2、caches.open():返回一个resolve为匹配 cacheName 的 cache 对象的 Promise .如果指定的 cache 不存在,则使用该 cacheName 创建一个新的cache并返回。

caches.open(cacheName).then(function(cache) {});

3、cache.addAll():将静态资源加入缓存中

cache.addAll(requests[]).then(function() {
  // 已加入缓存
});

该方法会覆盖掉以前存储在缓存中的匹配的健值对,但是后面监听对fetch事件中调用cache.put()方法又会覆盖掉之前在cache.addAll()中添加到缓存中所匹配的健值对。
4、cache.put():允许将键/值对添加到当前的 Cache 对象中.它将覆盖先前存储在匹配请求的cache中的任何键/值对。
注意: Cache.add/Cache.addAll 不会缓存 Response.status 值不在200范围内的响应,而 Cache.put 允许你存储任何请求/响应对。因此,Cache.add/Cache.addAll 不能用于不透明的响应,而 Cache.put 可以。

cache.put(request, response).then(function() {
  // request/response pair has been added to the cache
});

5、event.waitUntil():扩展了事件的生命周期。在服务工作线程中,延长事件的寿命从而阻止浏览器在事件中的异步操作完成之前终止服务工作线程。
install事件中,它延迟将被安装的worker视为 installing ,直到传递的 Promise 被成功地resolve。主要用于确保:服务工作线程在所有依赖的核心cache被缓存之前都不会被安装。
activate事件中,它延迟将 active worker视为已激活的,直到传递的 Promise 被成功地resolve。这主要用于确保:任何功能事件不会被分派到 ServiceWorkerGlobalScope 对象,直到它升级数据库模式并删除过期的缓存条目。
当该方法运行时,如果 Promise 是resolved,任何事情都不会发生;如果 Promise 是rejected,installing 或者 active worker的 state 会被设置为redundant。
语法:event.waitUntil(promise)
6、event.respondWith():阻止浏览器默认的fetch处理方法,允许用户自己提供一个promise对象作为response返回。

fetchEvent.respondWith(
  // Promise that resolves to a Response.
​)

Parameters:A Promise for a Response.

上面的sw.js只是一个最基本的serviceWorker,在日常工作中,我们还需要考虑更新。

四、Service Worker更新

(一)自动更新

this.addEventListener('install',function(event){
    this.skipWaiting();
});
this.addEventListener('activate', function (event) {
    this.clients.claim();
});

skipWaiting(): 强制等待中的service worker跳过等待成为激活的service worker。虽然该方法在任何时候都是可以调用的,但是只有在新安装的service worker仍然处于等待状态时才会起作用;所以在install事件里面调用是非常常见的。与clients.claim()一起调用以确保更新当前的client和其他激活的clients。
clients.claim(): 允许一个激活的service worker将其设置为其他同scope下的clients的controller。该方法会触发要被该service worker控制的其他任何clients的navigator.serviceWorker上的"controllerchange"事件。
当一个service worker初始注册时并不会使用该service worker,直到下次加载页面时。该方法会让这些页面直接被控制,注意,这将导致你的service worker将控制定期加载的页面,也有可能控制其他service worker加载的页面。

(二)手动更新

手动更新主要是调用在index.html注册serviceWorker时的registration的update()方法:ServiceWorkerRegistration.update();
它会获取worker的脚本URL,如果新的worker与当前的worker并不是完全相同的(byte-by-byte identical)则安装新的worker;如果前一次worker获取发生在24小时之前,则worker的获取将绕过任何浏览器缓存。

navigator.serviceWorker.register('./sw.js').then(function(registration){
   registration.update();
});

参考学习链接:
https://developer.mozilla.org...
https://developers.google.cn/...
https://lavas.baidu.com/pwa/o...
https://segmentfault.com/a/11...

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Wesley13 Wesley13
3年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
美凌格栋栋酱 美凌格栋栋酱
4个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(