service worker的基本知识

媒介: 看到一篇解说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的基本知识》

  1. 注册service worker,在网页上见效
  2. 装置胜利,激活 或许 装置失利(下次加载会尝试从新装置)
  3. 激活后,在sw的作用域下作用一切的页面,初次控制sw不会见效,下次加载页面才会见效。
  4. 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 */ });

能够自定义返回的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 就装置胜利了。假如任何一个文件下载失利,那末装置步骤就会失利。这个体式格局依靠于你本身指定的资本,但这意味着,你须要异常细致地肯定哪些文件须要被缓存。指定了太多文件的话,会增添失利率。

  • 对缓存跟返回请求的处置惩罚
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,我们举行以下的搜检:

1. 确保 response 有用
2. 搜检 response 的状况是200
3. 确保 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);
          }
        })
      );
    })
  );
});
    原文作者:槐破梦
    原文地址: https://segmentfault.com/a/1190000019106428
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞