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生命周期

  

  1. 注册service worker,在网页上生效

  2. 安装成功,激活 或者 安装失败(下次加载会尝试重新安装)

  3. 激活后,在sw的作用域下作用所有的页面,首次控制sw不会生效,下次加载页面才会生效。

  4. sw作用页面后,处理fetch(网络请求)和message(页面消息)事件 或者 被终止(节省内存)。

需要提前掌握的API

  1. 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');
});

  

  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的使用

  1. 兼容低版本,注入Cache API的一个polyfill,Service Worker需要依赖Cache API:
self.importScripts('./serviceworker-cache-polyfill.js');

  

  1. 注册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/)。

  1. 安装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 就安装成功了。如果任何一个文件下载失败,那么安装步骤就会失败。这个方式依赖于你自己指定的资源,但这意味着,你需要非常仔细地确定哪些文件需要被缓存。指定了太多文件的话,会增加失败率。

  1. 缓存和返回请求
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,一份到浏览器,一份到缓存中缓存。

  1. 重新激活

你的 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://davidwalsh.name/cache

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://davidwalsh.name/cache

https://zhuanlan.zhihu.com/p/20040372

https://zhuanlan.zhihu.com/p/28161855

https://www.villainhr.com/page/2017/01/08/Service Worker 全面进阶

Service Worker基础知识整理的更多相关文章

  1. Kali Linux渗透基础知识整理(四):维持访问

    Kali Linux渗透基础知识整理系列文章回顾 维持访问 在获得了目标系统的访问权之后,攻击者需要进一步维持这一访问权限.使用木马程序.后门程序和rootkit来达到这一目的.维持访问是一种艺术形式 ...

  2. Kali Linux渗透基础知识整理(二)漏洞扫描

    Kali Linux渗透基础知识整理系列文章回顾 漏洞扫描 网络流量 Nmap Hping3 Nessus whatweb DirBuster joomscan WPScan 网络流量 网络流量就是网 ...

  3. 【OGG】OGG基础知识整理

    [OGG]OGG基础知识整理 一.GoldenGate介绍 GoldenGate软件是一种基于日志的结构化数据复制软件.GoldenGate 能够实现大量交易数据的实时捕捉.变换和投递,实现源数据库与 ...

  4. java部分基础知识整理----百度脑图版

    近期发现,通过百度脑图可以很好的归纳总结和整理知识点,本着学习和复习的目的,梳理了一下java部分的知识点,不定期更新,若有不恰之处,请指正,谢谢! 脑图链接如下:java部分基础知识整理----百度 ...

  5. wifi基础知识整理

    转自 :http://blog.chinaunix.net/uid-9525959-id-3326047.html WIFI基本知识整理 这里对wifi的802.11协议中比较常见的知识做一个基本的总 ...

  6. Linux基础知识整理

    一.基础知识 1.Linux简介 Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户.多任务.支持多线程和多CPU的操作系统.它能运行主要的UNIX工具软件 ...

  7. JavaScript基础知识整理

    只整理基础知识中关键技术,旨在系统性的学习和备忘. 1.在 JScript 中 null 和 undefined 的主要区别是 null 的操作象数字 0,而 undefined 的操作象特殊值NaN ...

  8. C#基础知识整理

    年时,北风吹雁雪纷纷,一条秋裤冻上头.冷的连手都懒得动,就随便翻翻书,也没有更新博客,如今年已过,开始投入到正常的工作状态中,趁现在需求还没有来,把C#基础知识梳理一下,其实一直以来就想这样做的,对于 ...

  9. Oracle ASM 磁盘组基础知识整理(收藏版)

    转至:https://cloud.tencent.com/developer/article/1494403 为什么要写这么一篇基础知识呢?还是有那么一点点原因的,不是胡编乱造还真是有真实存在的事件的 ...

随机推荐

  1. BZOJ_1266_[AHOI2006]上学路线route_最小割

    BZOJ_1266_[AHOI2006]上学路线route_最小割 Description 可可和卡卡家住合肥市的东郊,每天上学他们都要转车多次才能到达市区西端的学校.直到有一天他们两人参加了学校的信 ...

  2. BZOJ_1269&&1507_[AHOI2006]文本编辑器editor&&[NOI2003]Editor

    BZOJ_1269&&1507_[AHOI2006]文本编辑器editor&&[NOI2003]Editor 题意: 分析: splay模拟即可 注意1507的读入格式 ...

  3. 猴子 JDFZ模拟赛

    猴子(弱) Description 话说NP做梦,梦见自己变成了一只猴子,并且有很多香蕉树,这些香蕉树都种在同一直线上,而NP则在这排香蕉树的第一棵树上.NP当然想吃尽量多的香蕉,但它又不想在地上走, ...

  4. Heartbeat实现集群高可用热备

    公司最近需要针对服务器实现热可用热备,这几天也一直在琢磨这个方面的东西,今天做了一些Heartbeat方面的工作,在此记录下来,给需要的人以参考. Heartbeat 项目是 Linux-HA 工程的 ...

  5. 显著性检测(saliency detection)评价指标之NSS的Matlab代码实现

    calcNSSscore.m function [ score ] = calcNSSscore( salMap, eyeMap ) %calcNSSscore Calculate NSS score ...

  6. Cocoa包管理器之CocoaPods详解

    CocoaPods在Cocoa开发日常工作中经常用到的包管理器,即依赖管理工具.有的项目也有用Carthage的,Carthage是一个比较新的依赖管理工具,是使用Swift语言开发的.Carthag ...

  7. TensorFlow之RNN:堆叠RNN、LSTM、GRU及双向LSTM

    RNN(Recurrent Neural Networks,循环神经网络)是一种具有短期记忆能力的神经网络模型,可以处理任意长度的序列,在自然语言处理中的应用非常广泛,比如机器翻译.文本生成.问答系统 ...

  8. 了解Scala反射

    本篇文章主要让大家理解什么是Scala的反射, 以及反射的分类, 反射的一些术语概念和一些简单的反射例子. 什么是反射 我们知道, Scala是基于JVM的语言, Scala编译器会将Scala代码编 ...

  9. ES 11 - 配置Elasticsearch的映射 (mapping)

    目录 1 映射的相关概念 1.1 什么是映射 1.2 映射的组成 1.3 元字段 1.4 字段的类型 2 如何配置mapping 2.1 创建mapping 2.2 更新mapping 2.3 查看m ...

  10. ES6之Promise学习与实践

    1.前言 在平时的业务开发中,前端通常需要请求后台获取数据,或者NodeJs读取文件等等一系列的异步操作,我们通常需要利用异步操作的结果或者对异步操作的结果进行处理.通常我们的解决方案是:在异步操作成 ...