PWA:渐进式网页应用、Service Worker 和清单的基础知识

作者: IT Sectr 发布日期: 2026-02-14 阅读时间: 10 分钟

PWA(渐进式网页应用)——是一种利用浏览器现代功能以像原生应用一样工作的网络应用程序:快速加载、离线工作、发送推送通知并可安装到主屏幕。PWA 的基础是三项技术:Service Worker、清单和 HTTPS。Service Worker ——是浏览器在后台独立于网页运行的脚本,它打开了普通网站无法实现的可能性:拦截网络请求、缓存资源、后台同步和推送通知。清单 ——是一个 JSON 文件,它告诉浏览器应用程序在设备上安装时应如何显示:名称、图标、主题颜色、屏幕方向。没有 HTTPS,Service Worker 就无法工作——这是一项强制性的安全要求。PWA 与任何现代浏览器兼容,无需在应用商店发布。用户打开网站,看到安装应用程序的提议,点击「添加到主屏幕」——应用程序就准备好了。对于企业来说,PWA 意味着无需单独为 iOS 和 Android 开发即可覆盖任何受众,即使在慢速网络上也能实现高速加载,并通过推送通知提高用户参与度。本文将分析 Service Worker 的工作原理、如何编写清单、使用哪些缓存策略以及如何实现离线访问。

要点

  • PWA——像原生一样工作的网络应用:安装到主屏幕、离线工作、发送推送通知
  • Service Worker——具有生命周期的后台 JS 脚本:注册、安装、激活、拦截网络请求
  • 缓存策略——针对不同类型的资源使用 Cache First、Network First、Stale While Revalidate
  • Web App Manifest——包含名称、图标、主题颜色和显示模式设置的 JSON 文件
  • 推送通知——通过 Push API 和 Notification API 工作,即使在应用关闭时也能工作
  • Lighthouse——PWA 审计工具,最低通过分数为 80/100
  • Workbox——Google 的库,用于简化 Service Worker 的创建和管理

要点

  • PWA——像原生一样工作的网络应用:安装到主屏幕、离线工作、发送推送通知
  • Service Worker——具有生命周期的后台 JS 脚本:注册、安装、激活、拦截网络请求
  • 缓存策略——针对不同类型的资源使用 Cache First、Network First、Stale While Revalidate
  • Web App Manifest——包含名称、图标、主题颜色和显示模式设置的 JSON 文件
  • 推送通知——通过 Push API 和 Notification API 工作,即使在应用关闭时也能工作
  • Lighthouse——PWA 审计工具,最低通过分数为 80/100
  • Workbox——Google 的库,用于简化 Service Worker 的创建和管理

什么是渐进式网页应用

渐进式网页应用(PWA)——是一种结合了网页和原生应用最佳品质的网络应用开发方法。该术语由 Francesco Berriman 于 2015 年提出,Google 积极推广 PWA 作为简单移动应用的替代品。核心思想:网站根据浏览器和设备的能力逐步增强。如果浏览器支持 Service Worker——连接离线模式。如果支持清单——出现「安装」按钮。如果有通知 API——应用程序可以发送推送。在弱设备上使用慢速互联网的用户将获得网站的基本版本,而在现代智能手机上,将获得带有桌面图标的完整应用程序。

PWA 无需通过应用商店安装。一个链接就足够了。这解决了移动应用的主要问题——高进入门槛。用户不必去 Google Play 或 App Store,不必等待 100 MB 的下载,不必授予十多项权限。他只需打开网站,浏览器就会提议安装应用程序。如果用户拒绝——他仍然可以使用网站。如果同意——图标出现在主屏幕上,应用程序像原生一样打开:没有浏览器地址栏、全屏模式、快速启动。

从技术上讲,PWA 必须满足三个标准:通过 HTTPS(安全连接)工作,拥有 Service Worker(后台处理脚本),并包含 清单(Web App Manifest)。这三个组件将普通网站转变为可安装的应用程序。

Service Worker:PWA 的心脏

Service Worker——是浏览器在独立线程中、独立于网页运行的 JavaScript 脚本。它无法访问 DOM,不能直接与界面交互,但可以拦截和修改网络请求、管理缓存、处理推送通知和执行后台同步。Service Worker 充当浏览器和网络之间的代理服务器:来自页面的每个请求都经过 Service Worker,由它决定——从缓存返回数据、从服务器请求还是两者都做。

Service Worker 按照自己的生命周期生存,不依赖于打开的页面。它被安装、激活,甚至在网站的所有标签页关闭后仍在后台工作。这使 PWA 能够在后台接收推送通知和更新缓存,无需用户参与。

Service Worker 的生命周期

Service Worker 经历四个阶段:注册、安装、激活和空闲/终止。

注册。浏览器获取 Service Worker 的 JS 文件链接并开始下载。注册从页面上的普通 JavaScript 执行:

javascript
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js')
    .then(registration => {
      console.log('SW 已注册:', registration.scope);
    })
    .catch(error => {
      console.log('SW 注册失败:', error);
    });
}

安装。成功下载后,浏览器触发 install 事件。在此阶段,通常会缓存关键资源(HTML 骨架、CSS、主要图像),以便应用程序可以离线工作。如果安装成功,Service Worker 进入下一阶段。如果脚本抛出错误——安装被取消,旧的 Service Worker 继续工作。

javascript
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open('pwa-cache-v1').then(cache => {
      return cache.addAll([
        '/',
        '/index.html',
        '/styles/main.css',
        '/scripts/app.js',
        '/images/logo.png'
      ]);
    })
  );
});

激活。当网站的所有标签页关闭时,旧的 Service Worker 终止,新的被激活。activate 事件用于清理旧缓存和数据迁移:

javascript
self.addEventListener('activate', event => {
  const cacheWhitelist = ['pwa-cache-v2'];
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.map(cacheName => {
          if (!cacheWhitelist.includes(cacheName)) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});

空闲。激活的 Service Worker 拦截请求并处理事件。它可能被浏览器停止以节省资源,并在下一次请求时重新启动。Service Worker 是事件驱动的:它只在处理事件时存活。

缓存策略

Service Worker 支持多种缓存策略。选择取决于资源类型和数据新鲜度要求。

Cache First(优先缓存)。首先检查缓存。如果找到资源——从缓存返回。如果没有——请求发送到服务器,响应保存在缓存中。该策略适用于静态资源:图像、字体、CSS、JS。提供最大速度和完整的离线工作。

javascript
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(response => {
      return response || fetch(event.request).then(fetchResponse => {
        return caches.open('pwa-cache-v1').then(cache => {
          cache.put(event.request, fetchResponse.clone());
          return fetchResponse;
        });
      });
    })
  );
});

Network First(优先网络)。请求首先发送到服务器。如果服务器响应——数据返回给用户并保存在缓存中。如果服务器不可用——返回缓存的副本。该策略适用于 API 请求、新闻、需要保持最新但也可以离线工作的内容。

javascript
self.addEventListener('fetch', event => {
  event.respondWith(
    fetch(event.request).then(response => {
      return caches.open('pwa-dynamic-v1').then(cache => {
        cache.put(event.request, response.clone());
        return response;
      });
    }).catch(() => {
      return caches.match(event.request);
    })
  );
});

Stale While Revalidate(过期但更新)。响应立即从缓存返回,同时在后台向服务器发送请求以更新缓存。用户立即看到内容,下一个请求将收到新鲜数据。适用于变化的内容,但如果用户看到晚几分钟的版本并不关键的情况。

javascript
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(cached => {
      const fetchPromise = fetch(event.request).then(response => {
        return caches.open('pwa-dynamic-v1').then(cache => {
          cache.put(event.request, response.clone());
          return response;
        });
      });
      return cached || fetchPromise;
    })
  );
});

Web App Manifest:应用程序在设备上的显示方式

清单——是一个 JSON 文件,通常是 manifest.json,通过 <link> 标签在 HTML 页面的 head 中连接。它告诉浏览器应用程序在设备上安装时应如何显示:名称、不同尺寸的图标、背景颜色、主题颜色、方向和显示模式(浏览器、最小 UI、全屏)。

json
{
  "name": "PWA Demo App",
  "short_name": "PWA Demo",
  "description": "演示 PWA 应用程序",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#3f51b5",
  "orientation": "portrait",
  "icons": [
    {
      "src": "/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "any maskable"
    }
  ]
}

display 参数决定应用程序在安装后的外观。standalone 隐藏浏览器地址栏和导航面板——应用程序看起来像原生应用。fullscreen 使用整个屏幕,没有任何浏览器元素。minimal-ui 保留最少的浏览器元素(返回和刷新按钮)。

图标应至少准备两种尺寸:192x192 和 512x512 像素。PNG 格式支持 purpose 参数(例如 maskable),允许浏览器根据设备外壳形状调整图标——在 Android 上,图标可能被裁剪为圆角方形。连接清单后,Android 上的 Chrome 浏览器在满足条件时开始显示「添加到主屏幕」横幅:HTTPS、已注册的 Service Worker、正确的清单以及至少两次访问,间隔 5 分钟。

PWA 中的推送通知

PWA 可以像原生应用一样发送推送通知。为此使用了两个 API:Push API(服务器发送)和 Notification API(在设备上显示)。Service Worker 即使应用未打开也能接收 push 事件,并可显示带有标题、文本和图标的通知。

要接收推送通知,用户必须授予权限:

javascript
Notification.requestPermission().then(permission => {
  if (permission === 'granted') {
    console.log('推送已允许');
  }
});

Service Worker 订阅 push 事件并显示通知:

javascript
self.addEventListener('push', event => {
  const data = event.data.json();
  self.registration.showNotification(data.title, {
    body: data.body,
    icon: '/icons/icon-192x192.png',
    badge: '/icons/badge-72x72.png',
    actions: [
      { action: 'open', title: '打开' },
      { action: 'close', title: '关闭' }
    ]
  });
});

self.addEventListener('notificationclick', event => {
  event.notification.close();
  if (event.action === 'open') {
    clients.openWindow('/');
  }
});

从服务器发送推送使用 Web Push(VAPID)协议。服务器加密消息并通过浏览器的推送服务(Chrome 使用 Firebase Cloud Messaging,Firefox 使用 Mozilla Autopush)发送。用户的订阅(PushSubscription 对象)需要在注册时保存在服务器上。

性能和 Lighthouse

PWA 必须快速。Google Lighthouse——是一个审计工具,它根据检查清单检查 PWA:Service Worker 注册、离线访问时的 200 响应、正确的清单、HTTPS、正确的图标大小、慢速网络上的快速加载。PWA 的最低通过分数——Lighthouse 量表上的 80/100。分数低于 80 的应用程序不会在 Chrome 中获得安装横幅。

PWA 的关键性能指标——First Contentful Paint(FCP)达到 1.8 秒、Largest Contentful Paint(LCP)达到 2.5 秒、Time to Interactive(TTI)达到 3.5 秒。Service Worker 如果在安装时缓存关键的 HTML 和 CSS,可以显著改善 FCP 和 LCP。Cache First 策略用于静态内容,Stale While Revalidate 用于 API,提供最佳用户体验。

离线访问和后台同步

PWA 的主要功能之一——无互联网工作。Service Worker 拦截请求并返回页面的缓存版本。如果用户尝试打开不在缓存中的页面,可以显示自定义的备用页面:

javascript
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(response => {
      return response || fetch(event.request);
    }).catch(() => {
      return caches.match('/offline.html');
    })
  );
});

后台同步(Background Sync)允许在设备离线时推迟向服务器发送数据。Service Worker 保存请求,并在连接恢复时自动发送:

javascript
self.addEventListener('sync', event => {
  if (event.tag === 'sync-messages') {
    event.waitUntil(sendMessages());
  }
});

function sendMessages() {
  return caches.open('pwa-pending-v1').then(cache => {
    return cache.keys().then(requests => {
      return Promise.all(requests.map(request => {
        return fetch(request).then(() => cache.delete(request));
      }));
    });
  });
}

PWA 开发工具

Chrome DevTools 提供 Application 面板,可在其中调试 Service Worker(注册、状态、缓存、推送)、检查清单、清除缓存和为测试创建自己的推送通知。带有离线模式模拟的 Network 选项卡有助于检查缓存工作。Audits 面板中的 Lighthouse 提供完整的 PWA 审计和推荐。

Workbox——Google 的库,简化了 Service Worker 的创建。Workbox 提供现成的模块,而不是手动编写缓存策略:

javascript
import { precacheAndRoute } from 'workbox-precaching';
import { registerRoute } from 'workbox-routing';
import { StaleWhileRevalidate } from 'workbox-strategies';

precacheAndRoute(self.__WB_MANIFEST);

registerRoute(
  /\.(?:png|jpg|jpeg|svg|gif)$/,
  new StaleWhileRevalidate()
);

Workbox 与打包工具(Webpack、Vite)集成,并自动生成预缓存清单。Microsoft 的 PWA Builder(pwabuilder.com)在线生成所有 PWA 文件:Service Worker、清单、图标、HTML 模板。

常见问题

用简单的话说 PWA 是什么?

PWA——是一个网站,安装到手机后像普通应用一样工作:桌面图标、离线访问、推送通知、没有浏览器地址栏的全屏模式。同时无需去 App Store 或 Google Play——从浏览器一键安装。

PWA 和原生应用有什么区别?

原生应用是为特定平台(iOS 用 Swift,Android 用 Kotlin)编写的,需要在商店发布和手动安装。PWA——是用 HTML、CSS 和 JavaScript 编写的网站,可以通过浏览器安装在设备上。PWA 占用空间小(仅缓存)、自动更新、被所有现代浏览器支持。

哪些浏览器支持 PWA?

Chrome、Firefox、Safari(从 iOS 11.3 开始)、Edge、Samsung Internet、Opera。Service Worker 被所有现代浏览器支持,除了 Internet Explorer。Safari 对推送通知的支持有限,但 PWA 的基本功能(安装到主屏幕、离线访问)可以工作。

能否将现有网站转换为 PWA?

可以。为此需要添加清单(manifest.json)、创建并注册 Service Worker(sw.js)、将网站切换到 HTTPS、添加元标签和图标。网站本身如果使用 JavaScript 并返回 HTML,则无需重写。如果网站完全是服务器端(MPA),可以添加 Service Worker 作为缓存层,无需更改架构。

PWA 如何更新?

当用户打开 PWA 时,浏览器检查服务器上的 Service Worker 文件是否已更改。如果文件至少相差一个字节,浏览器下载新的 Service Worker 并开始安装。旧的 Service Worker 继续工作,直到应用程序的所有标签页关闭。标签页关闭后,新的 Service Worker 激活并取代旧的。用户可以通过重新加载页面来强制更新应用程序。

是否值得开发 PWA 而不是移动应用?

PWA 是合理的,如果目标是覆盖最大受众而无需为两个平台开发成本,如果应用程序不需要深度访问硬件(蓝牙、NFC、后台摄像头),如果内容频繁变化。对于复杂的应用程序(游戏、视频编辑器),原生应用仍然是首选。PWA 通常用作补充渠道或作为完整应用程序之前的 MVP。

总结

  • PWA(渐进式网页应用)——像原生一样工作的网络应用:安装到主屏幕、离线工作、发送推送通知。
  • PWA 的三个必需组件:HTTPS、Service Worker 和清单(manifest.json)。缺少任何一个元素,浏览器都不会提供安装。
  • Service Worker——拦截网络请求的后台 JavaScript 脚本。实现缓存策略:Cache First(静态)、Network First(API)、Stale While Revalidate(带更新内容)。
  • Web App Manifest——包含显示设置的 JSON 文件:名称、图标、主题颜色、display(standalone、fullscreen、minimal-ui)。图标需要 192x192 和 512x512 尺寸。
  • 推送通知在 PWA 中通过 Push API 和 Notification API 工作。Service Worker 即使在应用关闭时也能接收 push 事件。
  • Lighthouse 根据检查清单检查 PWA。安装的最低分数——80/100。关键指标:FCP 达到 1.8 秒,LCP 达到 2.5 秒。
  • Workbox 来自 Google,简化 Service Worker 开发:现成策略、自动缓存、与打包工具集成。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读