ServiceWorker是什么?

发布时间:2023-05-20

ServiceWorker 是 PWA 技术栈中的一个重要成员,它是一个用于使 Web 应用在离线状态下依然可以工作,且具有网络拦截的浏览器功能。这个功能由一段运行在浏览器后台线程的 JavaScript 代码来实现。

一、ServiceWorker的作用

ServiceWorker 的主要功能是使得 Web 应用程序可以离线运行。通过 ServiceWorker 可以缓存 Web 应用在用户设备上的一些文件,如 HTML、JS、CSS、图片等,这样即使用户离线,也能通过 ServiceWorker 的缓存功能加载并渲染对应的 Web 应用页面。 另外,ServiceWorker 还能够通过网络拦截功能对接口的请求做一些处理,这可以用于 Offline First 等场景的开发。例如当 Web 应用在用户设备上没有网络或者网络差的情况下,ServiceWorker 可以使用它的缓存功能提供一些基础信息或者降级处理。当然,ServiceWorker 的功能不止这些,还可以配合 Push Notification 等技术进行 Web 应用的推送、更新等操作。

二、ServiceWorker无效的原因

ServiceWorker 运行的环境比较独特,它没有 window 或 document 的对象,也没有 localStorage 或者 indexedDB 之类的浏览器 API。这样导致 ServiceWorker 中某些操作是不能进行的。 另外,由于 ServiceWorker 运行在后台线程之中,所以为了确保不会出现异常情况,ServiceWorker 只能响应 HTTPS 或者本地环境,这也是 ServiceWorker 无法应用到经典的 HTTP 协议中的一个原因。

三、阮一峰关于ServiceWorker的看法

阮一峰在他的博客中提到过 ServiceWorker:“ServiceWorker 与 Web Worker 非常相似,都是运行在浏览器后台的 JavaScript 线程。ServiceWorker 和传统浏览器 js 不同,它可以脱离标签页运行,具有比较高的独立性,因此可以进行一些操作,比如缓存、推送等。” 在他的看来,ServiceWorker 是一种比较快捷、简便的技术,可以极大地提升 Web 应用的易用性和性能体验。

四、ServiceWorker拦截请求

ServiceWorker 提供了一个对请求的拦截功能,在 ServiceWorker 中可以通过拦截特定类型的请求,例如接口请求或者资源请求,从而完成一些特殊的处理。

self.addEventListener('fetch', (event) => {
  if (event.request.url.includes('your-api-url.com')) {
    event.respondWith(fetch(event.request).then((res) => {
      return res.json().then((data) => {
        return new Response(JSON.stringify(data));
      });
    }));
  }
});

上述代码中,我们监听了 fetch 事件,如果检测到该请求地址包含是某个 API 地址,则会使用 ServiceWorker 拦截该请求,然后获取响应结果进行数据相关处理后返回。

五、ServiceWorkers是什么意思

ServiceWorkers 是指一类服务工作线程。ServiceWorker 是一种比较新的 HTML5 技术,它们被设计成运行在浏览器后台线程。 ServiceWorker 不会和浏览器标签页之间产生显著的交互,这使得它们可以被用于离线应用程序、消息推送、后台数据同步和其他类似的任务。ServiceWorker 的 API 本质上就是 Web Worker API 的一种,但提供了更多的能力和一些不同的限制。

六、ServiceWorker和Web Worker

ServiceWorker 和 Web Worker 非常相似,它们都是后台线程,都不能访问 DOM,提供了新的 JavaScript Worker 类,是 HTML5 中新添加的一种运行在浏览器后台的线程。 在 ServiceWorker 和 Web Worker 中,JavaScript 代码是一个独立的线程,不会阻塞主线程,允许同时做多件事情。

七、苹果ServiceWorker

苹果公司已经支持 ServiceWorker 技术,苹果 Safari 浏览器在 2017 年 6 月份开始支持 ServiceWorker 的注册和使用,这对 PWA 应用的普及有着极为重要的意义。

八、Service worker 与负责可靠实时交付的网络应用程序

ServiceWorker 可以让慢速和不可靠的网络情况下的 Web 应用程序依然能够拥有较好的用户体验。通过 ServiceWorker 的事件监听功能,开发者可以在网络离线的情况下,选择返回本地缓存提供用户一些基础信息,避免 Web 应用程序传输许多陈旧和冗余的数据。 此外,Service Worker 还为开发者提供了对本地缓存的实时控制功能,可以根据具体情况灵活调整缓存策略,可以选择在页面初始化或者在网络上下文变化之后更新缓存。

九、Service Worker 在浏览器的支持情况

目前支持 ServiceWorker 的主流浏览器有:

  • Chrome 45+
  • Firefox 44+
  • Opera 32+
  • Edge 17+
  • Safari 11.1+ Safari 目前仅支持 HTTPS 环境下的 ServiceWorker。

十、Service Workers 的完整示例代码

const CACHE_NAME = 'my-site-cache-v1';
const URLS_TO_CACHE = [
  '/',
  '/styles/main.css',
  '/scripts/main.js',
  '/images/logo.png',
  '/pages/offline.html'
];
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then((cache) => {
        return cache.addAll(URLS_TO_CACHE);
      })
  );
});
self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request)
      .then((response) => {
        if (response) {
          return response;
        }
        return fetch(event.request);
      })
      .catch(() => {
        return caches.match('/pages/offline.html');
      })
  );
});
self.addEventListener('activate', (event) => {
  const cacheWhitelist = ['my-site-cache-v2'];
  event.waitUntil(
    caches.keys()
      .then((cacheNames) => {
        return Promise.all(
          cacheNames.map((cacheName) => {
            if (cacheWhitelist.indexOf(cacheName) === -1) {
              return caches.delete(cacheName);
            }
          })
        );
      })
      .then(() => {
        return self.clients.claim();
      })
  );
});

上述代码就是一个 ServiceWorker 实现离线缓存的完整代码示例。它安装和激活之后就会缓存指定的内容,后面在网络不可达的情况下,会从缓存中读取相应资源。如果缓存不存在,会返回缺省的 offline.html 页面。