Service Worker基础知识整理
Service Worker是什么
service worker 是独立于当前页面的一段运行在浏览器后台进程里的脚本。它的特性将包括推送消息,背景后台同步, geofencing(地理围栏定位),拦截和处理网络请求。
这个 API 会让人兴奋的原因是,它可以使你的应用先访问本地缓存资源,所以在离线状态时,在没有通过网络接收到更多的数据前,仍可以提供基本的功能(一般称之为 Offline First)。
在 service worker 之前,另一个叫做 APP Cache 的 api 也可以提供离线体验。APP Cache 的的主要问题是坑比较多,而且其被设计为只适合于单页 web 应用程序,对于传统的多页网站则不适合。service worker 的设计规避了这些痛点。
关于 service worker 的一些注意点:
- service worker 是一个JavaScript worker ,所以它不能直接访问 DOM 。但 service worker 可以通过postMessage 接口与跟其相关的页面进行通信,发送消息,从而让这些页面在有需要的时候去操纵 DOM 。
- Service worker 是一个可编程的网络代理,允许你去控制如何处理页面的网络请求, 可以处理fetch请求。
- Service worker 在不使用时将被终止,并会在需要的时候重新启动,因此你不能把onfetch 和 onmessage事件来作为全局依赖处理程序。如果你需要持久话一些信息并在重新启动Service worker后使用他,可以使用 IndexedDBAPI ,service worker 支持。
- Service Worker 的缓存机制是依赖 Cache API 实现的
- Service worker 广泛使用了 promise。
- Service worker依赖 HTML5 fetch API
- Service Workers 要求必须在 HTTPS 下才能运行
Service Worker生命周期

注册service worker,在网页上生效
安装成功,激活 或者 安装失败(下次加载会尝试重新安装)
激活后,在sw的作用域下作用所有的页面,首次控制sw不会生效,下次加载页面才会生效。
sw作用页面后,处理fetch(网络请求)和message(页面消息)事件 或者 被终止(节省内存)。
需要提前掌握的API
- Cache API基本使用
(1)检测api是否存在
if('caches' in window) {
// Has support!
}
(2)caches.open,创建缓存总对象。如下创建名为 test-cache 的缓存。
caches.open('test-cache').then(function(cache) {
// Cache is created and accessible
});
(3)cache.add和cache.addAll,添加缓存内容。其中cache.add只添加一个,cache.addAll可以添加多个。
caches.open('test-cache').then(function(cache) {
cache.addAll(['/', '/images/logo.png'])
.then(function() {
// Cached!
// or use cache.add
cache.add('/page/1'); // "/page/1" URL will be fetched and cached!
});
});
(4)cache.keys(),查看已经缓存的数据
caches.open('test-cache').then(function(cache) {
cache.keys().then(function(cachedRequests) {
console.log(cachedRequests); // [Request, Request]
});
});
(5)cache.match和cache.matchAll,匹配缓存文件路径
caches.open('test-cache').then(function(cache) {
cache.match('/page/1').then(function(matchedResponse) {
console.log(matchedResponse);
});
});
(6)cache.delete,删除缓存。
caches.open('test-cache').then(function(cache) {
cache.delete('/page/1');
});
- Fetch API基本使用
// url (required), options (optional)
fetch('https://davidwalsh.name/some/url', {
method: 'get'
}).then(function(response) { }).catch(function(err) {
// Error :(
});
其中options对象包含以下属性:
- method - GET, POST, PUT, DELETE, HEAD
- url - 请求的链接
- headers - 请求的header对象
- referrer - 请求的referrer对象
- mode - cors, no-cors, same-origin
- credentials - 设置请求可不可以携带cookie
- redirect - follow, error, manual
- integrity - 子资源完整值
- cache - 缓存模式 (default, reload, no-cache)
可以在fetch中传入Request对象实例:
var request = new Request('https://davidwalsh.name/users.json', {
method: 'POST',
mode: 'cors',
redirect: 'follow',
headers: new Headers({
'Content-Type': 'text/plain'
})
});
// Now use it!
fetch(request).then(function() { /* handle response */ });
(3)可以自定义返回的Response对象实例,其中的options有:
- type - basic, cors
- url
- useFinalURL - 上面的url参数是不是最终的URL
- status - 状态码(ex: 200, 404, etc.)
- ok - 是否成功响应 (范围在 200-299)
- statusText - 状态码 (ex: OK)
- headers - 响应的headers对象
另外Response的实例还具备以下方法:
- clone() - 创建Response对象的克隆。
- error() - 返回与网络错误关联的新Response对象。
- redirect() - 使用不同的URL创建新响应。
- arrayBuffer() - 返回使用ArrayBuffer解析的promise。
- blob() - 返回使用Blob解析的promise。
- formData() - 返回使用FormData对象解析的promise。
- json() - 返回使用JSON对象解析的promise。
- text() - 返回使用USVString(文本)解析的promise。
// Create your own response for service worker testing
// new Response(BODY, OPTIONS)
var response = new Response('.....', {
ok: false,
status: 404,
url: '/'
}); // The fetch's `then` gets a Response instance back
fetch('https://davidwalsh.name/')
.then(function(responseObj) {
console.log('status: ', responseObj.status);
});
Service Worker的使用
- 兼容低版本,注入Cache API的一个polyfill,Service Worker需要依赖Cache API:
self.importScripts('./serviceworker-cache-polyfill.js');
- 注册service worker:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js').then(function(registration) {
// Registration was successful
console.log('ServiceWorker registration successful with scope: ', registration.scope);
}).catch(function(err) {
// registration failed :(
console.log('ServiceWorker registration failed: ', err);
});
}
上面的代码检查 service worker API 是否可用,如果可用, /sw.js 这个文件将会作为 service worker 被注册。
如果这个 service worker 已经被注册过,浏览器会自动忽略上面的代码。
有一个特别要注意是 service worker 文件的路径。你一定注意到,在这个例子中,service worker 文件被放在这个域的根目录下,这意味着 service worker是跟网站同源的。换句话说,这个 service worker 将会获取到这个域下的所有 fetch 事件。如果 service worker文件注册到/example/sw.js ,那么 service worker 只能收到 /example/ 路径下的 fetch 事件(比如: /example/page1/, /example/page2/)。
- 安装service worker:
var CACHE_NAME = 'my-site-cache-v1';
var urlsToCache = [
'/',
'/styles/main.css',
'/script/main.js'
]; self.addEventListener('install', function(event) {
// Perform install steps
event.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
console.log('Opened cache');
return cache.addAll(urlsToCache);
})
);
});
上面代码声明了需要缓存的内容,如果所有的文件都缓存成功,service worker 就安装成功了。如果任何一个文件下载失败,那么安装步骤就会失败。这个方式依赖于你自己指定的资源,但这意味着,你需要非常仔细地确定哪些文件需要被缓存。指定了太多文件的话,会增加失败率。
- 缓存和返回请求
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
// IMPORTANT: Clone the request. A request is a stream and
// can only be consumed once. Since we are consuming this
// once by cache and once by the browser for fetch, we need
// to clone the response
var fetchRequest = event.request.clone();
return fetch(fetchRequest).then(
function(response) {
// Check if we received a valid response
if(!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// IMPORTANT: Clone the response. A response is a stream
// and because we want the browser to consume the response
// as well as the cache consuming the response, we need
// to clone it so we have 2 stream.
var responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(function(cache) {
cache.put(event.request, responseToCache);
});
return response;
}
);
})
);
如果我们想在缓存中添加新的请求缓存,可以通过处理fetch请求的response,将其添加到缓存中即可。代码里我们做了以下事情:
添加一个 callback 到 fetch 请求的 .then 方法中。 一旦我们获得一个 response,我们进行如下的检查:
- 确保 response 有效
- 检查 response 的状态是200
- 确保 response 的类型是 basic 类型的,这说明请求是同源的,这意味着第三方的请求不能被缓存。
如果检查通过会clone 这个请求。这么做的原因是如果 response 是一个 Stream,那么它的 body 只能被消费一次。所以为了让浏览器跟缓存都使用这个body,我们必须克隆这个 body,一份到浏览器,一份到缓存中缓存。
- 重新激活
你的 service worker 总会有要更新的时候。在那时,你需要按照以下步骤来更新:
更新你 service worker 的 JavaScript 文件 当用户浏览你的网站时,浏览器尝试在后台重新下载 service worker 的脚本文件。经过对比,只要服务器上的文件和本地文件有一个字节不同,这个文件就认为是新的。
之后更新后的 service worker 启动并触发 install 事件。
此时,当前页面生效的依然是老版本的 service worker,新的 service worker 会进入 “waiting” 状态。
当页面关闭之后,老的 service worker 会被干掉,新的 servicer worker 接管页面 一旦新的 service worker 生效后会触发 activate 事件。 通常来讲,需要在 activate 的 callback 中进行 cache 管理,来清理老的 cache。我们在 activate 而不是 install 的时候进行的原因,是如果我们在 install 的时候进行清理,那么老的 service worker 仍然在控制页面,他们依赖的缓存就失效了,因此就会突然被停止。
之前我们使用的缓存可以叫 my-site-cache-v1 ,我们想把这个拆封到多个缓存,一份给页面使用,一份给博客文章使用。这意味着,install 步骤里,我们要创建两个缓存: pages-cache-v1 和 blog-posts-cache-v1。在 activite 步骤里,我们需要删除旧的 my-site-cache-v1。
下面的代码会遍历所有的缓存,并删除掉不在 cacheWhitelist 数组(我们定义的缓存白名单)中的缓存。
self.addEventListener('activate', function(event) {
var cacheWhitelist = ['pages-cache-v1', 'blog-posts-cache-v1'];
event.waitUntil(
caches.keys().then(function(cacheNames) {
return Promise.all(
cacheNames.map(function(cacheName) {
if (cacheWhitelist.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
})
);
})
);
});
参考文章
http://kailian.github.io/2017/03/01/service-worker
https://juejin.im/post/5ba0fe356fb9a05d2c43a25c
https://developer.mozilla.org/zh-CN/docs/Web/API/Service_Worker_API/Using_Service_Workers
https://lavas.baidu.com/doc/offline-and-cache-loading/service-worker/how-to-use-service-worker
https://zhuanlan.zhihu.com/p/20040372
https://zhuanlan.zhihu.com/p/28161855
https://www.villainhr.com/page/2017/01/08/Service Worker 全面进阶
Service Worker基础知识整理的更多相关文章
- Kali Linux渗透基础知识整理(四):维持访问
Kali Linux渗透基础知识整理系列文章回顾 维持访问 在获得了目标系统的访问权之后,攻击者需要进一步维持这一访问权限.使用木马程序.后门程序和rootkit来达到这一目的.维持访问是一种艺术形式 ...
- Kali Linux渗透基础知识整理(二)漏洞扫描
Kali Linux渗透基础知识整理系列文章回顾 漏洞扫描 网络流量 Nmap Hping3 Nessus whatweb DirBuster joomscan WPScan 网络流量 网络流量就是网 ...
- 【OGG】OGG基础知识整理
[OGG]OGG基础知识整理 一.GoldenGate介绍 GoldenGate软件是一种基于日志的结构化数据复制软件.GoldenGate 能够实现大量交易数据的实时捕捉.变换和投递,实现源数据库与 ...
- java部分基础知识整理----百度脑图版
近期发现,通过百度脑图可以很好的归纳总结和整理知识点,本着学习和复习的目的,梳理了一下java部分的知识点,不定期更新,若有不恰之处,请指正,谢谢! 脑图链接如下:java部分基础知识整理----百度 ...
- wifi基础知识整理
转自 :http://blog.chinaunix.net/uid-9525959-id-3326047.html WIFI基本知识整理 这里对wifi的802.11协议中比较常见的知识做一个基本的总 ...
- Linux基础知识整理
一.基础知识 1.Linux简介 Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户.多任务.支持多线程和多CPU的操作系统.它能运行主要的UNIX工具软件 ...
- JavaScript基础知识整理
只整理基础知识中关键技术,旨在系统性的学习和备忘. 1.在 JScript 中 null 和 undefined 的主要区别是 null 的操作象数字 0,而 undefined 的操作象特殊值NaN ...
- C#基础知识整理
年时,北风吹雁雪纷纷,一条秋裤冻上头.冷的连手都懒得动,就随便翻翻书,也没有更新博客,如今年已过,开始投入到正常的工作状态中,趁现在需求还没有来,把C#基础知识梳理一下,其实一直以来就想这样做的,对于 ...
- Oracle ASM 磁盘组基础知识整理(收藏版)
转至:https://cloud.tencent.com/developer/article/1494403 为什么要写这么一篇基础知识呢?还是有那么一点点原因的,不是胡编乱造还真是有真实存在的事件的 ...
随机推荐
- C#进度框
1.方法一:使用线程 功能描述:在用c#做WinFrom开发的过程中.我们经常需要用到进度条(ProgressBar)用于显示进度信息.这时候我们可能就需要用到多线程,如果不采用多线程控制进度条,窗口 ...
- 自动化测试框架 hierarchyViewer、Uiautomator、Appium的区别比较!
一.HierarchyViewer: 优点:1)能够可视化的角度直观地获得UI布局设计结构和各种属性的信息 2)使用hierarchyviewer.bat来检索手机界面布局 缺点:1)稳定性差,出现过 ...
- zookeeper配置管理+集群管理实战
引言 之前就了解过kafka,看的似懂非懂,最近项目组中引入了kafka,刚好接着这个机会再次学习下. Kafka在很多公司被用作分布式高性能消息队列,kafka之前我只用过redis的list来做简 ...
- git解析日志常用命令
git diff --name-only ORIG_HEAD 获取变更列表 git log -p 查看每个提交引入的实际更改. git log --oneline --decorate 查看日志列表 ...
- python接口自动化(十六)--参数关联接口后传(详解)
简介 大家对前边的自动化新建任务之后,接着对这个新建任务操作了解之后,希望带小伙伴进一步巩固胜利的果实,夯实基础.因此再在沙场实例演练一下博客园的相关接口.我们用自动化发随笔之后,要想接着对这篇随笔操 ...
- Javascript的内存泄漏分析
作为程序员(更高大尚的称谓:研软件研发)的我们,无论是用Javascript,还是.net, java语言,肯定都遇到过内存泄漏的问题.只不过他们都有GC机制来帮助程序员完成内存回收的事情,如果你是C ...
- 设计模式之过滤器模式——Java语言描述
过滤器模式允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来 实现 创建一个Person对象.Criteria 接口和实现了该接口的实体类,来过滤 Person 对象的列 ...
- HTML 练习绑定onclick事件
方法一 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8 ...
- oracle创建表空间自增长和创建用户
/* 步骤: 1.创建表空间 2.创建用户 3.用户授权 */ /*创建表空间*/ create tablespace QCJ_TABLESPACE /*表空间物理文件名称*/ datafile 'Q ...
- 2、自动化运维之SaltStack远程执行详解
SaltStack远程执行详解 ●目标(Targeting) ●模块(Module) ●返回(Returnners) 混合模式-C 选项 主机名设置参照: redis-node1-redis03-id ...