认识 Service Worker

Service Worker 是一个运行在浏览器后台的 JavaScript 脚本,独立于网页主线程,是构建渐进式 Web 应用(PWA)的核心技术。它作为浏览器与网络之间的代理,可以实现离线访问、消息推送、后台同步等原生应用般的功能。

Service Worker 的主要特点:

  • 独立线程:不会阻塞页面渲染,也无法直接操作 DOM。

  • 网络代理:可以拦截页面发出的所有网络请求,并决定如何响应

  • 事件驱动:生命周期由一系列事件(install、activate、fetch 等)驱动

  • 需要 HTTPS:出于安全考虑,Service Worker 只在 HTTPS(或 localhost)环境下生效

js 复制代码
if ("serviceWorker" in navigator) {
  const swUrl = new URL("./sw.js", window.location.href);
  const swScope = new URL("./", window.location.href).pathname;

  navigator.serviceWorker
    .register(swUrl, { scope: swScope })
    .then((reg) => console.log("SW registered", reg.scope))
    .catch((err) => console.error("SW registration failed", err));

  navigator.serviceWorker.ready.then(() => {
    console.log("Service Worker 已就绪");
  });

  navigator.serviceWorker.oncontrollerchange = () => {
    console.log("Service Worker 已激活");
  };
}

async function fetchData() {
  const resultDiv = document.getElementById("result");
  resultDiv.textContent = "正在请求中...";

  try {
    const response = await fetch(
      "https://jsonplaceholder.typicode.com/posts/1"
    );

    if (!response.ok) {
      throw new Error(`HTTP 错误!状态码:${response.status}`);
    }

    const data = await response.json();
    resultDiv.textContent = "请求成功!\n\n" + JSON.stringify(data, null, 2);
  } catch (error) {
    resultDiv.textContent = "请求失败:" + error.message;
    console.error("错误:", error);
  }
}

new URL() 是 JavaScript 内置的构造函数,用于解析和构建 URL 地址。它返回一个 URL 对象,该对象包含 URL 的各个组成部分(如协议、主机名、路径、查询参数等),并提供了方便的属性和方法来操作 URL。

new URL() 构造函数接受两个参数:要解析的 URL 地址和可选的基 URL 地址。如果省略了基 URL 地址,则默认为 undefined

如果 new URL()传入的第一个参数 url 是相对路径,则必须提供 base(基准 URL)来解析成完整地址。

如果传人的第一个参数 url 是绝对路径,则 base 参数将被忽略。

js 复制代码
new URL(url);
new URL(url, base);
js 复制代码
// 使用传入的相对 url 和基 url 构造一个绝对 url
const swUrl = new URL("./sw.js", window.location.href);

serviceWorker.register()scope 参数指定了 Service Worker 能够控制的范围,也就是它能拦截哪些路径下的网络请求。

如果不指定 scope,Service Worker 默认控制脚本所在目录及其子目录。例如,如果脚本在 /js/sw.js,则默认控制 /js/ 及更深的路径(如 /js/page/)。

设置 scope: "/" 表示整个网站(同源下所有页面)都会被该 Service Worker 拦截。如果设置 scope: "/admin/",则只有以 /admin/ 开头的页面和请求会被控制。

scope 不能超出脚本所在的路径层级。即 Service Worker 只能控制与其同目录或子目录的范围,不能控制父目录(除非脚本位于根目录,才能设置 scope: "/")。

js 复制代码
navigator.serviceWorker.register(swUrl, { scope: swScope });

oncontrollerchange 事件在当前页面所关联的 Service Worker 控制器(controller)发生变化时触发。

js 复制代码
navigator.serviceWorker.oncontrollerchange = () => {
  console.log("Service Worker 已激活");
};

Service Worker 有 4 个生命周期,该生命周期由浏览器管理,主要分为以下阶段:

  1. 注册(Registration):页面通过 JavaScript 告诉浏览器 Service Worker 脚本的位置。

  2. 安装(Install):首次注册或版本更新时触发,适合预缓存静态资源。

  3. 激活(Activate):安装成功后触发,可用于清理旧缓存、接管页面。

  4. 空闲/终止:当没有事件需要处理时,浏览器会终止 Service Worker 以节省内存,下次需要时再唤醒。

sw.js 文件内容如下:

js 复制代码
self.addEventListener("install", () => {
  console.log("安装");
  self.skipWaiting(); // 跳过等待,直接激活
});

self.addEventListener("activate", (event) => {
  console.log("激活");
  event.waitUntil(self.clients.claim()); // 立即接管所有页面
});

self.addEventListener("fetch", (event) => {
  console.log("Service Worker 拦截到请求:", event.request.url);
  event.respondWith(fetch(event.request));
});

fetchXMLHttpRequest 的一个很大区别是,fetch 可以在 Service Worker 中使用。

self.skipWaiting() 的作用是让新安装的 Service Worker 跳过 waiting 阶段,尽快进入 active 状态 。

正常流程里,新的 SW 安装后会先 waiting ,要等旧 SW 不再控制任何页面才会激活。

调用 self.skipWaiting() 后,新 SW 不用等那么久,会尝试立即激活。

clients.claim() 让"已激活 SW 立刻接管页面"。

event.waitUntil() 的作用是: 告诉浏览器"这个事件还有异步任务没完成,请先别结束" 。

监听 fetch 事件的作用是:拦截当前 Service Worker 作用域内的所有网络请求,并决定如何返回响应 。

event.respondWith(fetch(event.request)) 把请求原样转发到网络,再把网络结果返回给页面。

event.respondWith()的作用是: 在 fetch 事件里接管这次请求,并指定返回给页面的响应。

总结

Service Worker 是运行在浏览器后台的独立线程脚本,作为浏览器与网络之间的代理,可用于离线访问、消息推送和后台同步等功能。

  • 核心特点:独立线程、事件驱动、可拦截网络请求、仅在 HTTPS(或 localhost)下生效。

  • 注册与路径 :通过 navigator.serviceWorker.register() 注册,常用 new URL() 构造 sw.js 路径;scope 用于限定控制范围,不能超出脚本所在目录。

  • 生命周期:四个阶段 ------ 注册(Registration)、安装(Install,可用于预缓存)、激活(Activate,可清理旧缓存并接管页面)、空闲/终止(节省资源,按需唤醒)。

  • 常用 API 与模式

    • self.skipWaiting()(跳过 waiting,快速激活)、
    • clients.claim()(激活后立即接管页面)、
    • event.waitUntil()(延长事件直至异步任务完成)、
    • fetch 事件中使用 event.respondWith() 拦截并返回响应。
  • 实践示例 :文中示例的 sw.js 展示了 installactivatefetch 的基本写法,以及在 fetch 中将请求透传到网络 event.respondWith(fetch(event.request)) 的简单用法。

以上要点概览了 Service Worker 的作用、注册方式、作用范围、生命周期与常见实现模式,便于快速上手和理解在实践中如何拦截与处理请求。

参考

Using Service Workers

相关推荐
Alan Lu Pop16 分钟前
前端开发助手
前端·智能体
程序员鱼皮17 分钟前
我用 GitHub 仓库养 AI 龙虾,自动开发上线项目!保姆级教程
前端·人工智能·ai·程序员·github·编程·ai编程
276695829230 分钟前
京东随机变速滑块拼图验证码识别(京东E卡)
java·服务器·前端·python·京东滑块·京东变速滑块·京东e卡绑卡
এ慕ོ冬℘゜1 小时前
手写生产级 jQuery Toast 轻量提示组件|零插件依赖、动画流畅、极简高
前端·javascript·jquery
Oneslide1 小时前
UI设计-企业OA风格
前端
程序员海军1 小时前
我用了 8 个月 Codex CLI,总结出这套 AI 编程工作流
前端·后端·aigc
大家的林语冰1 小时前
Express 团队官宣:全新网站正式上线,Logo 重做,支持两个主版本文档无缝切换!
javascript·node.js·express
এ慕ོ冬℘゜2 小时前
手写一款高兼容、零BUG图片预览组件|前端
前端·bug
铁链鞭策大师2 小时前
javaEE之多线程(2)
java·前端·java-ee
KaMeidebaby2 小时前
卡梅德生物技术快报|生信实操:ChIP 染色质免疫共沉淀技术流程、短板与替代方案详解
前端·人工智能·物联网·百度·新浪微博