前端缓存 Service workers 详解

Service Worker 是什么

Service Worker 是一个在浏览器中运行的 JavaScript 脚本,它为Web应用程序提供了一种在后台执行的机制。它的主要用途是处理离线缓存、推送通知、网络请求拦截和消息传递等功能,这些功能可以改善Web应用程序的性能和用户体验。

Service Worker运行在一个独立的线程中,因此它不会阻塞主页面的渲染和用户交互,从而改善了性能。然而,由于它的强大功能和潜在的安全风险,使用Service Worker需要小心谨慎,确保安全性和合理性。

Service Worker 主要特点和用途是什么那

  1. 离线缓存:Service Worker可以将网站资源(如HTML、CSS、JavaScript、图像等)缓存到本地,使网站能够在离线状态下继续运行。这提供了更好的离线体验,尤其在移动设备上或网络不稳定的环境中。

  2. 网络请求拦截:Service Worker可以拦截网页发出的网络请求,从缓存中获取资源,或者将请求代理到服务器。这允许开发人员实施自定义的缓存策略,以提高性能和效率。

  3. 推送通知:Service Worker允许网站发送推送通知,即使网站并未打开在浏览器中。这对于实时通知用户非常有用,例如新消息、提醒或更新。

  4. 后台同步:Service Worker可以在后台执行任务,例如数据同步或更新,而无需打开网站。这对于定期更新数据或执行其他自动化任务很有用。

  5. 消息传递:Service Worker可以与页面之间以及与服务器进行双向通信,这为构建高度交互性的Web应用程序提供了便利。

Service Worker 生命周期是什么

  • 注册 :首次访问页面时,浏览器会尝试注册一个 Service Worker 脚本。你通常在页面中使用 JavaScript 的 navigator.serviceWorker.register() 方法来进行注册。
  • 安装 :当 Service Worker 脚本成功注册时,它会执行 install 事件处理程序。在这个事件处理程序中,你可以缓存网站的静态资源,以便在以后离线使用。通常,这个阶段用于初始化 Service Worker。
  • 激活:一旦 Service Worker 安装成功,浏览器会尝试激活新的 Service Worker。在激活阶段,你可以执行清理旧缓存、删除不再需要的资源等操作。Service Worker 只有在成功激活后才能控制客户端的网络请求。
  • 控制客户端:一旦 Service Worker 被激活,它可以控制与之关联的客户端,包括网页或其他客户端。在这个阶段,Service Worker 可以拦截网络请求、处理推送通知、接收消息等。它会持续运行,直到被注销或停止。
  • 更新:当你更新 Service Worker 脚本时,浏览器会检测到新版本,并将其下载。新版本的 Service Worker 会经历安装、激活和控制客户端的阶段,以确保平稳的过渡。通常,你可以在新版本的 Service Worker 中更新缓存或执行其他操作,以提供更好的用户体验
  • 注销 :Service Worker 可以被手动注销,或者在脚本中调用 self.skipWaiting() 方法来强制激活新版本。这可以用于确保新的 Service Worker 能够立即控制客户端,而不需要等待旧版本自然过期。

Service Worker 用法

Service Worker 如何注册

注册 Service Worker:使用 navigator.serviceWorker.register() 方法注册 Service Worker。通常,这会在页面加载时或在合适的时机执行。

javascript 复制代码
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/service-worker.js')
    .then((registration) => {
      console.log('Service Worker registered with scope:', registration.scope);
    })
    .catch((error) => {
      console.error('Service Worker registration failed:', error);
    });
}

在上述代码中,navigator.serviceWorker.register('/service-worker.js') 会尝试注册位于根目录下的 service-worker.js 文件作为 Service Worker。

处理注册成功和失败:register() 方法返回一个 Promise,可以使用 .then() 处理注册成功的情况,以及使用 .catch() 处理注册失败的情况。在注册成功后,你可以获得一个包含有关 Service Worker 注册的信息的对象,如上述代码所示。

请注意,Service Worker 必须位于与网页相同的域中,以便进行注册。否则,由于安全策略的限制,Service Worker 无法注册成功。

一旦 Service Worker 注册成功,它将开始安装并激活,然后可以开始控制与之关联的客户端(例如网页),执行缓存、网络请求拦截、推送通知等任务。

Service Worker 如何控制客户端

  1. 拦截和处理网络请求:Service Worker 可以通过拦截客户端发出的网络请求来控制它们。你可以检查请求,从缓存中获取响应,或者将请求代理到服务器。这使你能够实现离线支持、缓存策略、网络请求重试等功能。

例如,下面是一个拦截并从缓存中获取资源的示例:

csharp 复制代码
self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((response) => {
      return response || fetch(event.request);
    })
  );
});
  1. 向客户端发送消息 :Service Worker 可以通过使用 postMessage 方法向客户端发送消息。客户端可以监听 message 事件以接收并响应消息。 在 Service Worker 中发送消息:
javascript 复制代码
self.clients.matchAll().then((clients) => {
  clients.forEach((client) => {
    client.postMessage('Hello from Service Worker!');
  });
});

在客户端中监听消息:

javascript 复制代码
navigator.serviceWorker.addEventListener('message', (event) => {
  console.log('Message from Service Worker:', event.data);
});
  1. 推送通知:Service Worker 可以用于处理推送通知,从服务器发送通知到客户端。一旦推送通知到达,Service Worker 可以展示通知或执行其他操作,以提醒用户或执行相关任务。
csharp 复制代码
self.addEventListener('push', (event) => {
  const options = {
    body: event.data.text(),
    icon: '/icon.png',
  };

  event.waitUntil(
    self.registration.showNotification('Push Notification', options)
  );
});
  1. 同步任务:Service Worker 还支持后台同步,这意味着它可以在客户端离线时执行任务,然后在网络连接可用时同步数据。

例如,你可以使用后台同步来上传离线时保存的数据到服务器:

csharp 复制代码
self.addEventListener('sync', (event) => {
  if (event.tag === 'sync-task') {
    // 执行同步任务
    event.waitUntil(doSyncTask());
  }
});

Service Worker 如何注销

要注销(解除注册)一个 Service Worker,你可以使用 navigator.serviceWorker.getRegistration()unregister() 方法。这允许你手动取消注册一个 Service Worker。 以下是一些步骤来注销 Service Worker: 获取 Service Worker 的注册:

  1. 首先,你需要获取当前已注册的 Service Worker。你可以使用 navigator.serviceWorker.getRegistration() 方法来获取 Service Worker 的注册对象。这将返回一个 Promise,包含 Service Worker 的注册信息。
scss 复制代码
navigator.serviceWorker.getRegistration()
  .then((registration) => {
    if (registration) {
      // 在这里执行注销操作
      // 一旦你获取到 Service Worker 的注册信息,你可以使用 `unregister()` 方法来注销它。
    }
  });
  1. 注销 Service Worker:
javascript 复制代码
navigator.serviceWorker.getRegistration()
  .then((registration) => {
    if (registration) {
      registration.unregister()
        .then((isUnregistered) => {
          if (isUnregistered) {
            console.log('Service Worker unregistered successfully.');
          } else {
            console.log('Service Worker was not unregistered.');
          }
        })
        .catch((error) => {
          console.error('Error while trying to unregister the Service Worker:', error);
        });
    }
  });

Service Worker 调试以及检查

javascript 复制代码
 service worker实际上提供的是本地缓存服务,所以和我们平时查看localStorage差不多,打开谷歌浏览
 器调试中心,在Application栏下,就能看到Service Woerkers,如图:

也可以通过右侧 取消注册 以及更新 进行手动触发

我们可以通过网络请求看到当前请求的一个状态

Service Worker 和其他缓存(如浏览器缓存、Web Storage、IndexedDB 等)之间有一些关键区别

  1. 位置

    • Service Worker 是一个在浏览器后台运行的 JavaScript 脚本,它能够拦截和处理网络请求,以及缓存响应数据。它通常用于实现离线缓存、推送通知和其他高级功能。
    • 浏览器缓存Web StorageIndexedDB 等是在浏览器前台运行的缓存机制,它们通常用于存储静态资源(如图片、CSS、JavaScript)、用户数据和应用程序状态。
  2. 用途

    • Service Worker 的主要目的是提供离线支持、网络请求拦截、推送通知和后台同步等功能,从而增强 Web 应用程序的性能和用户体验。
    • 浏览器缓存 用于存储静态资源,以减少资源加载时间和带宽消耗。
    • Web StorageIndexedDB 通常用于存储应用程序的用户数据、会话信息和应用程序状态。
  3. 网络请求控制

    • Service Worker 具有强大的网络请求控制能力,它可以拦截和处理网络请求,从缓存中获取响应,甚至将请求代理到服务器。
    • 浏览器缓存 通常依赖于浏览器的默认缓存策略,但可以通过 HTTP 标头进行控制。
    • Web StorageIndexedDB 不直接与网络请求相关,而是用于本地存储数据。
  4. 离线支持

    • Service Worker 是设计用来提供离线支持的,它可以使网页在离线状态下仍然能够运行。
    • 浏览器缓存 通常缓存静态资源,但不提供离线支持。
    • Web StorageIndexedDB 也不提供离线支持,它们依赖于浏览器的在线状态。
  5. 事件驱动

    • Service Worker 是事件驱动的,它可以响应网络请求、推送通知和其他事件。

    • 浏览器缓存Web StorageIndexedDB 不是事件驱动的,它们通常需要手动操作来读取和写入数据

    总的来说,Service Worker 是一个强大的工具,可用于增强 Web 应用程序的性能和功能,特别是在离线和实时通知方面。其他缓存机制通常用于存储静态资源和用户数据,但它们不提供 Service Worker 的高级功能。在开发 Web 应用程序时,你可以根据需求选择合适的缓存机制。

相关推荐
腾讯TNTWeb前端团队3 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰7 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪7 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪7 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy8 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom8 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom8 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom8 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom9 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom9 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试