service workers是什么

什么是service workers,什么是service workers,如果你想知道什么是service workers,就让我来带你研究

认识service workers

什么是service workers

一个服务器与浏览器之间的中间人角色,如果网站中注册了service worker那么它可以拦截当前网站所有的请求,进行判断(需要编写相应的判断程序),如果需要向服务器发起请求的就转给服务器,如果可以直接使用缓存的就直接返回缓存不再转给服务器。从而大大提高浏览体验。

  • 基于web worker(一个独立于JavaScript主线程的独立线程,在里面执行需要消耗大量资源的操作不会堵塞主线程)
  • 在web worker的基础上增加了离线缓存的能力
  • 本质上充当Web应用程序(服务器)与浏览器之间的代理服务器(可以拦截全站的请求,并作出相应的动作->由开发者指定的动作)
  • 创建有效的离线体验(将一些不常更新的内容缓存在浏览器,提高访问体验)
  • 由事件驱动的,具有生命周期
  • 可以访问cache和indexDB
  • 支持推送
  • 并且可以让开发者自己控制管理缓存的内容以及版本

注意

Service worker运行在worker上下文 --> 不能访问DOM

它设计为完全异步,同步API(如XHR和localStorage)不能在service worker中使用

出于安全考量,Service workers只能由HTTPS承载

在Firefox浏览器的用户隐私模式,Service Worker不可用

其生命周期与页面无关(关联页面未关闭时,它也可以退出,没有关联页面时,它也可以启动)

一个简单的小demo

  1. 注册Service worker 在你的index.html加入以下内容
/* 判断当前浏览器是否支持serviceWorker */
    if ('serviceWorker' in navigator) {
        /* 当页面加载完成就创建一个serviceWorker */
        window.addEventListener('load', function () {
            /* 创建并指定对应的执行内容 */
            /* scope 参数是可选的,可以用来指定你想让 service worker 控制的内容的子目录。 在这个例子里,我们指定了 '/',表示 根网域下的所有内容。这也是默认值。 */
            navigator.serviceWorker.register('./serviceWorker.js', {scope: './'})
                .then(function (registration) {
 
                    console.log('ServiceWorker registration successful with scope: ', registration.scope);
                })
                .catch(function (err) {
 
                    console.log('ServiceWorker registration failed: ', err);
                });
        });
    }
  1. 安装worker:在我们指定的处理程序serviceWorker.js中书写对应的安装及拦截逻辑
/* 监听安装事件,install 事件一般是被用来设置你的浏览器的离线缓存逻辑 */
this.addEventListener('install', function (event) {
 	
    /* 通过这个方法可以防止缓存未完成,就关闭serviceWorker */
    event.waitUntil(
        /* 创建一个名叫V1的缓存版本 */
        caches.open('v1').then(function (cache) {
            /* 指定要缓存的内容,地址为相对于跟域名的访问路径 */
            return cache.addAll([
                './index.html'
            ]);
        })
    );
});

/* 注册fetch事件,拦截全站的请求 */
this.addEventListener('fetch', function(event) {
  event.respondWith(
    // magic goes here
      
      /* 在缓存中匹配对应请求资源直接返回 */
    caches.match(event.request)
  );
});

生命周期

Service Worker的初次运行生命周期流程如下图所示,从未注册开始主要分为Installed, Activated, IDLE 等阶段。

img

不同生命周期阶段转移的细节:

img

注册

在Service Worker被安装之前,首先需要在HTML页面内的脚本里注册server worker的脚本,即前面提到过的特定格式的JavaScript见(例如: sw.js)。注册这一步是在运行网页自身的脚本时告知浏览器:

这个页面是使用了Service Worker的,请加载指定路径的Service Worker的脚本并将它安装到当前域。

这一步本身不属于Service Worker的生命周期,因为它是需要在页面脚本里完成的,这和WebSocket比较类似。如下面的脚本(注意:它必须是HTML页面中script标签的一部分,而不是sw.js中的):

if ('serviceWorker' in navigator) {
 navigator.serviceWorker.register('/sw.js').then(function(registration) {
   // Registration was successful
   console.log(':) Success. ', registration.scope);
 }, function(err) {
   // registration failed :(
   console.log(':( Failed. ', err);
 });
}

上面的代码为当前页面所在的域注册了sw.js,我们还可以使用***scope***为它的指定更为细分的范围。也就是说,只有发送往当前域中来自scope中指定子路径的请求才会被Service Worker拦截,其他路径的请求将不受影响。如下图代码,只有向”https://domain/app/“及其子路径作为url的请求才会被service-worker.js里绑定的事件响应。

navigator.serviceWorker.register('/service-worker.js', {
  scope: '/app/'
});

若scope未被指定,那么默认的scope是获取service worker脚本所在的同级域,及其响应的子域。

生命周期事件

Service Worker中的主要生命周期阶段的变化,是通过事件来通知脚本的,所以Serice Worker的脚本主要需要做的是为不同生命周期事件绑定好对应的处理器。核心的生命周期事件处理器如图示:

img

下载事件 (Dowload)

下载事件未在上图中标出,它发生在脚本注册阶段被触发且由浏览器处理: 1) 从指定路径下载service worker的脚本; 2) 完成脚本的解析,如果不符合service worker脚本的规范则不会触发安装事件; 3) 正确的脚本被安装到浏览器的Service Worker列表,被触发安装事件; 下载失败,解析失败或者初始化错误引发的错误也可以在浏览器的开发者工具 -> 应用 -> Service Worker列表看到,

img

安装事件 (Install)

在下载事件被浏览器响应完成后,安装事件是Service Worker生命周期中第一个被触发的,所以它非常重要。我们通常使用它来完成各种初始化任务,主要是资源的预加载、缓存以及持久化一些长期有效的状态。

这里主要被使用的是Cache API,监听到安装事件就可以预先拉取一些资源,并在应用缓存中存储它们并用给定的名字标识,参见下面的代码示例。在下文中有关于API的更详细的内容。

const CACHE_NAME = 'my-site-cache-v1';
const urlsToCache = [  // The list of resources to cache
  '/',
  '/styles/main.css',
  '/script/main.js'
];

self.addEventListener('install', event => {
  // Perform install steps
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(function(cache) {
        console.log('Opened cache');
        return cache.addAll(urlsToCache);
      })
  );
});

鉴于Service Worker本质上类似于Web Worker,它的资源加载完全独立于页面进程,所以它完全不会影响首屏渲染的性能。当然了,我们也完全不能预期在首次加载中就能受到应用缓存带来的优化。

激活事件 (activate)

当Service Worker已经就绪,可以控制页面请求并处理功能事件如fetch,pushsync,激活事件就会被触发,我们监听激活事件的处理器就可以响应。

self.addEventListener('activate', event => {
  console.log('V1 now ready to handle fetches!');
});

激活事件标志着从这之后的请求将被Service Worker接管,所以通常用于区分Service Worker接管前后的分隔。 但这不意味着当前这次有效完成".register()"的页面会受到Service Worker 管理,因为我们无法预测页面资源先获取完成还是激活事件先响应。

请求事件 (fetch)

fetch事件被触发于页面对网络发起任意请求,当然我们前面已经提过:1)必须在激活事件触发后service worker接管网络请求;2)请求的目标url必须位于注册的资源范围(scope)内。

来看一下这个 demo, 这里Service Worker劫持了"fetch"请求,但只在激活后才会生效:

  1. 当你第一次打开这个demo页面,你应该在等待后看到一张狗的图片,因为这个页面的标签指向的就是一张dog.svg。对这个图片的请求在完成Service Worker的注册之前就已经发出去了,响应的自然是狗的图片。
  2. 然后刷新页面,这一次我们看到的却是猫的剪影图片了,之后反复刷新都会是猫的图片。因为Service Worker已经完成了注册,开始接管对图片资源的HTTP请求,并将我们的请求换成它准备好的猫图了。

我们来看看SW的脚本里都做了什么:

// Caching the cat image when installing
self.addEventListener('install', event => {
  console.log('V2 installing…');

  // cache a horse SVG into a new cache, static-v2
  event.waitUntil(
    caches.open('static-v2').then(cache => cache.add('/cat.svg'))
  );
});

// Response the cat image when requesting dog.
self.addEventListener('fetch', event => {
  const url = new URL(event.request.url);  
  // serve the cat SVG from the cache if the request is
  // same-origin and the path is '/dog.svg'
  if (url.origin == location.origin && url.pathname.endsWith('/dog.svg')) {
    event.respondWith(caches.match('cat.svg'));
  }
});
  • 在安装事件中,service worker请求了猫图cat.svg并加入缓存,这是页面进程完全不知道的。
  • 而在fetch事件中,我们劫持了网络请求,当资源目标为狗图时,service worker没有乖乖地转发请求,而是从缓存列表取出猫图,回复给了页面。同样,我们的页面并不知道这个请求根本没有通过网络,而是被service worker返回的资源应付了。就会有这张猫图在页面的资源列表里被标注成了请求的dog.svg的奇妙效果:

img

在上面提到的Service Worker的开发这界面,我们可以通过点击"unregiter"来取消当前service worker脚本的注册,这样在下一次打开时虽然service worker会被再次注册,至少在那一次的页面我们见到的将还是狗图了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值