Skip to main content

Service Work

Service workers 是一个在浏览器背后运行的脚步,独立于 web 页面,是一个注册在指定源和路径下的事件驱动 worker--可由脚本创建的后台任务,任务执行中可以向其创建者收发信息

它采用JavaScript控制关联的页面或者网站,拦截并修改访问和资源请求

注意: service worker的注册日志记录在Chrome浏览器中可以通过访问 chrome://serviceworker-internals 查看。

加载流程#

[图片来源 https://lavas-project.github.io/pwa-book/chapter04/3-service-worker-dive.html]

特点#

  1. 独立于网站运行: 运行在其他线程中,所以不会造成阻塞
  2. 无法操作DOM
  3. 只能使用 HTTPS 或者 localhost
  4. 可以拦截全站请求
  5. 完全异步,无法使用XHR和localStorage
  6. 独立上下文
  7. 作用域与页面路径相关

使用#

servicework.html#

servicework.html 注册 sw.js

<script>    //实际对应ServiceWorkerRegistration.active    var serviceWorker = navigator.serviceWorker.controller    //判断是否支持servicework    if ('serviceWorker' in navigator) {        //注册sw scope 设置sw的作用域        navigator.serviceWorker.register('sw.js', { scope: './' })            .then((registration) => {                console.log("register success");            }).catch((error) => {                console.log("regist failure ", error)            });    }    //创建一个通知用于与sw 双向通信    const messageChannel = new MessageChannel();    //监听sw发送过来的信息    messageChannel.port1.onmessage = function (event) {        console.log(`Response from the SW : ${event.data.command}`);    }    //向sw发送信息    serviceWorker.postMessage({ command: "connect"}, [messageChannel.port2]);    
    //注销sw    function logOff(){        console.log("logoff");        navigator.serviceWorker.getRegistration("./").then((registration)=>{            if(registration){                console.log("unregister");                registration.unregister();            }        })    }</script>

sw.js#

self.addEventListener('install', function (event) {    console.log("install", event)    self.skipWaiting();// sw立即生效,并将之前的销毁})self.addEventListener('activate', function (event) {    console.log("activate", event)    //让没被控制的 clients(页面、workers) 受控, 否则要刷新页面才受控    self.clients.claim();})//用于向主线程发送信息的通道channel = nullself.addEventListener('message', function (event) {    //获取主线程发送过来的信息    const data = event.data;    if (data.command === "connect") {        channel = event.ports[0];        //向主线程发送信息        channel.postMessage({ command: "accept" });    }})
//页面fetch 监听self.addEventListener('fetch', function (event) {    console.log('Handling fetch event for', event.request.url);    event.respondWith(        caches.match(event.request).then(function (response) {            if (response) {                console.log('Found response in cache:', response);                return response;            }            console.log('No response found in cache. About to fetch from network...');            return fetch(event.request).then(function (response) {                console.log('Response from network is:', response);                return response;            }).catch(function (error) {                console.error('Fetching failed:', error);                throw error;            });        })    );});

参考文档#

Service Worker 简介

工具#

sw-tool

workbox github

workbox get-started

使用场景#

  1. 缓存
  2. 后台运算
  3. 消息通知