news 2026/5/19 16:56:09

用户打开飞行模式都能打开你的网站?Service Worker 做离线缓存,PWA 实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用户打开飞行模式都能打开你的网站?Service Worker 做离线缓存,PWA 实战

你坐飞机,关掉网络,旁边小哥还在刷抖音(离线缓存好的视频)。你打开自己的网站,白屏,报错。你默默关上手机,心想:“要是我的网站也能离线看就好了。” 今天我们就来给你的网站装上“离线小精灵”——Service Worker。以后用户没网也能访问,还能把网站装到手机桌面,像原生 App 一样。

前言

PWA(Progressive Web App)这个概念喊了好几年,但真正用上的网站不多。其实它没那么玄乎,核心就是Service Worker——一个在浏览器后台独立运行的 JS 线程,能拦截网络请求、缓存资源、推送通知。

加了 Service Worker 的网站,就算用户开飞行模式,只要之前访问过,照样能看到页面(至少看到缓存过的内容)。而且速度极快,因为资源从本地取,不用等网络。今天我们就从零给一个静态网站加上离线缓存,顺便让它“可安装”。

一、Service Worker 生命周期:四步走

Service Worker 不是一上来就接管所有请求的,它有严格的生命周期:

  1. 注册:主线程告诉浏览器:“嘿,去下载这个 sw.js 文件。”
  2. 安装:浏览器下载、解析、执行 sw.js 里的install事件。通常在这里缓存核心资源。
  3. 激活:旧 Service Worker 被替换,新 SW 接管控制权。可以在activate事件里清理旧缓存。
  4. 空闲/运行:之后所有 fetch 请求都会被 SW 拦截。

注意:SW 只在 HTTPS(或 localhost)下生效,因为可以拦截网络,不安全。

二、最简单的 Service Worker:离线回退页面

我们先写一个极简版sw.js,让用户离线时看到一个“你已离线”的页面。

// sw.jsconstCACHE_NAME='my-pwa-cache-v1';constOFFLINE_URL='/offline.html';// 安装时缓存离线页面self.addEventListener('install',(event)=>{event.waitUntil(caches.open(CACHE_NAME).then((cache)=>cache.add(OFFLINE_URL)));// 强制等待中的 SW 立即激活self.skipWaiting();});// 激活时清理旧缓存self.addEventListener('activate',(event)=>{event.waitUntil(caches.keys().then((keys)=>{returnPromise.all(keys.filter(key=>key!==CACHE_NAME).map(key=>caches.delete(key)));}));self.clients.claim();});// 拦截请求,离线时返回缓存self.addEventListener('fetch',(event)=>{if(event.request.mode==='navigate'){// 页面导航请求event.respondWith(fetch(event.request).catch(()=>caches.match(OFFLINE_URL)));}else{// 其他资源走缓存优先策略(稍后优化)event.respondWith(caches.match(event.request).then((response)=>{returnresponse||fetch(event.request);}));}});

然后在index.html里注册:

<script>if('serviceWorker'innavigator){window.addEventListener('load',()=>{navigator.serviceWorker.register('/sw.js').then(reg=>{console.log('SW 注册成功',reg);}).catch(err=>{console.log('SW 注册失败',err);});});}</script>

现在你打开网站,开飞机模式(或 DevTools → Network 离线),刷新页面,应该会显示offline.html。说明 SW 已经拦下了请求。

三、缓存策略:别把所有鸡蛋放一个篮子

上面的代码对所有资源都用了“缓存优先”——先查 cache,没有才网络。这会导致一个问题:如果某个资源之前缓存过,即使服务器更新了,用户也看不到新版本。所以需要根据资源类型选择策略。

常用策略:

  • Cache First(缓存优先):适合不常变的图片、字体、CSS 库。速度快。
  • Network First(网络优先):适合 API 数据、HTML 页面。先尝试网络,失败再读缓存。
  • Stale-While-Revalidate:先返回缓存(如果有),同时后台更新缓存。兼顾速度和新鲜度。
  • 仅网络:永远不缓存(如支付接口)。
  • 仅缓存:永远从缓存取(如离线页面)。

我们改一下fetch事件:

self.addEventListener('fetch',(event)=>{consturl=newURL(event.request.url);// 如果是 API 请求,走网络优先if(url.pathname.startsWith('/api/')){event.respondWith(fetch(event.request).catch(()=>caches.match(event.request)));return;}// 如果是静态资源(js、css、图片),走缓存优先if(/\.(js|css|png|jpg|webp)$/.test(url.pathname)){event.respondWith(caches.match(event.request).then((cached)=>cached||fetch(event.request)));return;}// 其他(如 HTML)走 stale-while-revalidateevent.respondWith(caches.open(CACHE_NAME).then(async(cache)=>{constcached=awaitcache.match(event.request);constfetchPromise=fetch(event.request).then((response)=>{cache.put(event.request,response.clone());returnresponse;}).catch(()=>cached);returncached||fetchPromise;}));});

这样,你的网站既能离线访问,又能及时更新动态内容。

四、用 Workbox 简化代码

手写缓存策略很麻烦,尤其还要处理版本、过期、缓存清理。Google 出品了Workbox,一套工具库,几行配置搞定复杂策略。

安装 Workbox CLI 或直接在 sw.js 里导入 CDN:

importScripts('https://storage.googleapis.com/workbox-cdn/releases/7.0.0/workbox-sw.js');const{registerRoute,strategies,cacheableResponse}=workbox;// 预缓存静态资源(构建时生成 manifest)workbox.precaching.precacheAndRoute(self.__WB_MANIFEST||[]);// 图片缓存策略registerRoute(({request})=>request.destination==='image',newstrategies.CacheFirst({cacheName:'images',plugins:[newcacheableResponse.CacheableResponsePlugin({statuses:[0,200]}),newworkbox.expiration.ExpirationPlugin({maxEntries:50,maxAgeSeconds:30*24*60*60})]}));// API 网络优先registerRoute(({url})=>url.pathname.startsWith('/api/'),newstrategies.NetworkFirst());

配合 webpack/vite 插件,可以自动生成预缓存清单,连install里的cache.add都不用手动写。

五、让网站可安装(添加到主屏幕)

PWA 另一大特性:用户可以像装 App 一样把网站装到手机桌面。需要满足三个条件:

  1. HTTPS(或 localhost)
  2. 注册了 Service Worker
  3. 有一个manifest.json文件,放在根目录

示例manifest.json

{"name":"我的离线网站","short_name":"离线站","start_url":"/","display":"standalone","theme_color":"#000000","background_color":"#ffffff","icons":[{"src":"/icon-192.png","sizes":"192x192","type":"image/png"},{"src":"/icon-512.png","sizes":"512x512","type":"image/png"}]}

index.html里引用:

<linkrel="manifest"href="/manifest.json">

之后用户访问网站,浏览器会在地址栏右侧弹出“安装 App”的提示。点一下,桌面就多了一个图标,打开后没有浏览器地址栏,像原生 App。

六、推送通知(可选彩蛋)

Service Worker 还能接收服务器推送的消息,即使网站没打开也能弹出通知。这需要用户授权和后台推送服务(比如 Firebase Cloud Messaging)。代码稍复杂,但可以实现“用户关掉浏览器,你也能给他发优惠券提醒”的效果。

七、实测数据:加了 SW 之后

我用一个 React 静态网站测试:

  • 未缓存:首次加载 1.8s,二次无网白屏。
  • 加了 Workbox 预缓存:首次 2.0s(多下载了 SW 和 manifest),二次无网打开 0.3s(完全离线)。
  • 页面切换速度提升明显,因为路由对应的 JS 也被缓存。

用户从“等待加载”变成“秒开”,体验提升 5 倍以上。

八、坑点与避坑

  • 更新缓存:修改文件后,用户可能还是旧版本。需要更新CACHE_NAME版本号,或者在预缓存时用rev(文件 hash)解决。Workbox 会自动处理。
  • localhost 测试:记得勾选 DevTools → Application → Service Workers → Update on reload,否则 SW 缓存会干扰。
  • 作用域:SW 默认作用域是sw.js所在目录,如果放在根目录,可以控制全站。放在js/下就只能控制js/路径。
  • 调试:Chrome DevTools 的 Application 面板可以看到所有缓存、SW 状态、推送通知。

九、总结:PWA 是前端的“离线外挂”

  • Service Worker 是浏览器后台独立线程,能拦截请求、缓存资源、推送通知。
  • 生命周期:注册 → 安装 → 激活 → fetch。
  • 缓存策略根据资源类型选择:Cache First、Network First、Stale-While-Revalidate。
  • 搭配 Workbox 可省去手写复杂缓存逻辑。
  • 加上 manifest.json 就能让网站“安装到桌面”。

下次你坐飞机,打开自己的 PWA 网站,不用网络也能刷内容。同事看了问:“你怎么做到的?” 你就可以把本文甩给他。


评论区聊聊:你的网站支持离线访问吗?遇到过哪些缓存更新问题?

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/18 16:04:15

Godot 4实时电影级海洋渲染:基于GPU FFT的物理模拟与工程实践

1. 项目概述&#xff1a;当海洋动力学遇上实时渲染如果你正在寻找一个能在Godot 4引擎里&#xff0c;以实时帧率渲染出电影级真实感海洋的方案&#xff0c;那么tessarakkt/godot4-oceanfft这个开源项目绝对值得你投入时间研究。它不是一个简单的材质球或者贴图动画&#xff0c;…

作者头像 李华
网站建设 2026/5/18 16:04:12

DWMBlurGlass终极指南:如何为Windows标题栏添加惊艳的透明效果

DWMBlurGlass终极指南&#xff1a;如何为Windows标题栏添加惊艳的透明效果 【免费下载链接】DWMBlurGlass Add custom effect to global system title bar, support win10 and win11. 项目地址: https://gitcode.com/gh_mirrors/dw/DWMBlurGlass 你是否厌倦了Windows系统…

作者头像 李华
网站建设 2026/5/19 16:05:40

嵌入式数据可视化:PicoClaw轻量级图表库的设计与实战

1. 项目概述&#xff1a;一个为PicoClaw定制的图表库如果你在嵌入式开发&#xff0c;特别是基于RP2040芯片的PicoClaw项目里折腾过数据可视化&#xff0c;那你肯定懂我的痛&#xff1a;想在那个小小的OLED屏幕上画个折线图、显示个柱状图&#xff0c;代码写得比业务逻辑还复杂。…

作者头像 李华
网站建设 2026/5/18 16:02:51

iOS设备激活锁解决方案:AppleRa1n全面解析与实战应用

iOS设备激活锁解决方案&#xff1a;AppleRa1n全面解析与实战应用 【免费下载链接】applera1n icloud bypass for ios 15-16 项目地址: https://gitcode.com/gh_mirrors/ap/applera1n 面对iOS设备激活锁的困扰&#xff0c;AppleRa1n为您提供了一种创新的技术方案。这款基…

作者头像 李华