红宝书第五十二讲:零基础PWA技术全解析:Service Worker + 离线缓存

资料取自《JavaScript高级程序设计(第5版)》
查看总目录:红宝书学习大纲

PWA(渐进式网页应用) = 像原生APP一样体验的网页,支持离线使用、推送通知,秘诀在于Service Worker


一、PWA是什么?手机里的"小程序"

核心能力 12

  • 📱 可安装到手机主屏幕(像App一样打开)
  • 🚫 断网可用(地铁里照样刷新闻)
  • 🆕 后台自动更新(无需手动刷新)

二、Service Worker:网站的智能管家

1. 生命周期 34

flowchart TD
    注册ServiceWorker --> 安装阶段[缓存必要文件]
    安装阶段 -->|成功| 激活阶段[替换旧缓存]
    激活阶段 --> 接管页面请求
  1. 注册:初次访问页面时,浏览器注册Service Worker(代码示例)4

    // 主页面代码(例如index.html)
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker.register('/sw.js') // 注册sw.js文件
     .then(() => console.log('注册成功!'));
    }
  2. 安装与缓存:在sw.js中定义缓存逻辑(资料1中的缓存机制)1

    // sw.js内容
    const CACHE_NAME = 'v1'; // 缓存版本
    const filesToCache = ['/', '/styles.css', '/app.js']; // 需缓存的文件
    
    self.addEventListener('install', (event) => {
      event.waitUntil(
     caches.open(CACHE_NAME)
       .then(cache => cache.addAll(filesToCache)) // 缓存文件!
      );
    });
  3. 拦截请求:优先从缓存响应请求,无缓存再访问网络 2

    graph TB
     A[拦截网络请求] --> B{请求类型判断}
     B -->|已缓存| C[返回缓存内容]
     B -->|未缓存| D[联网获取并保存]
    // sw.js中的fetch事件监听
    self.addEventListener('fetch', (event) => {
      event.respondWith(
     caches.match(event.request) // 查找缓存
       .then(response => response || fetch(event.request)) // 无缓存则请求网络
      );
    });

三、手把手实现离线缓存

1. 注册Service Worker

// 📄 main.js (主页面)
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js').then(() => {
    console.log('管家已上岗!');
  });
}

2. 设置缓存规则

// 📄 sw.js (Service Worker脚本)
const CACHE_NAME = 'v1-缓存包';
const urlsToCache = ['/', '/style.css', '/app.js'];

// 📦 安装阶段:打包缓存
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(cache => cache.addAll(urlsToCache))
  );
});

// 🔄 拦截请求:优先用缓存
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => response || fetch(event.request))
  );
});

四、缓存更新流程图解

sequenceDiagram
    participant 用户
    participant ServiceWorker
    participant 服务器
  
    用户->>ServiceWorker: 发起资源请求
    ServiceWorker->>缓存: 查找是否有缓存
    缓存-->>ServiceWorker: 返回缓存结果
    alt 有缓存
        ServiceWorker->>用户: 立即返回缓存
    else 无缓存
        ServiceWorker->>服务器: 转发请求
        服务器-->>ServiceWorker: 返回新资源
        ServiceWorker->>缓存: 保存新版本
        ServiceWorker->>用户: 返回新资源
    end

五、进阶技巧:动态更新机制

// 🆕 版本更新时触发
self.addEventListener('activate', event => {
  const cacheWhitelist = ['v2-新缓存包'];

  event.waitUntil(
    caches.keys().then(cacheNames => 
      Promise.all(
        cacheNames.map(name => {
          if (!cacheWhitelist.includes(name)) {
            return caches.delete(name); // 🗑️ 清理旧缓存
          }
        })
      )
    )
  );
});

六、PWA配置清单:让网站变"App"

// 📄 manifest.json
{
  "name": "天气助手",
  "short_name": "天气",
  "start_url": "/",
  "display": "standalone", // 📱 全屏模式
  "icons": [{
    "src": "icon-192.png",
    "sizes": "192x192",
    "type": "image/png"
  }]
}

验证工具

  • Lighthouse检测(Chrome开发者工具内置)
  • 离线模式测试(Chrome → Network → Offline)

七、Service Worker的核心作用

  1. 网络代理:拦截网页请求,决定使用缓存还是重新获取 2
  2. 离线缓存:预先缓存关键资源(HTML、CSS、JS),断网时仍可用 1
  3. 后台运行:即使关闭浏览器标签,也能处理推送通知 5

八、离线使用的实际效果

  • 首次访问:缓存styles.cssapp.js等文件。
  • 断网后再次访问:Service Worker直接返回缓存内容,页面正常展示!

九、优势与注意事项

优势

  • 快速加载:缓存资源不用重复下载(资料6中的加速效果)。
  • 可靠体验:地铁、山区等弱网环境仍可用。

注意事项

  • HTTPS必需:Service Worker只能在安全域名下生效 6
  • 更新策略:修改文件后需更新缓存版本(如CACHE_NAME = 'v2'3

目录:总目录
上篇文章:红宝书第五十一讲:Web Components:创造你自己的HTML标签

下篇文章:红宝书第五十三讲:Google JavaScript代码规范(简化版):让代码像乐高一样整齐

脚注


  1. 《JavaScript高级程序设计(第5版)》Service Worker可实现离线访问和推送通知,是PWA的核心技术
  2. 《JavaScript高级程序设计(第5版)》Service Worker缓存资源包括HTML/CSS/JS,保证离线可用
  3. 《JavaScript高级程序设计(第5版)》描述了Service Worker的生命周期管理
  4. 《JavaScript高级程序设计(第5版)》展示了如何通过navigator.serviceWorker注册
  5. 《JavaScript高级程序设计(第5版)》提到Service Worker支持后台运行及推送通知
  6. 《JavaScript高级程序设计(第5版)》Service Worker作为网络代理拦截请求,管理缓存资源

kovli
13 声望7 粉丝