HOOOS

Service Worker实战:构建离线可用的PWA网站

0 83 技术宅小Z PWAService Worker离线缓存
Apple

你想过没有,为什么手机 App 能离线使用,而大部分网页不行?其实,通过 PWA(Progressive Web App)技术,网页也能做到!今天,咱就来聊聊 PWA 的核心技术——Service Worker,手把手教你搭建一个离线也能用的网站。

什么是 Service Worker?

简单来说,Service Worker 就是一个在浏览器后台默默运行的脚本。它就像一个“中间人”,拦截并处理网页发出的所有请求。有了它,咱们就能实现离线缓存、消息推送等神奇的功能。

想象一下,你正在地铁上看一篇新闻,突然没信号了!普通网页肯定加载不出来,但如果这个网站用了 Service Worker,它就能从本地缓存中取出内容,让你继续阅读。是不是很酷?

Service Worker 的生命周期

要用好 Service Worker,得先搞懂它的“一生”:

  1. 注册(Registration):告诉浏览器,咱要用 Service Worker 了。
  2. 安装(Installation):Service Worker 开始下载并安装自己。
  3. 激活(Activation):安装完成后,Service Worker 正式上岗,开始控制页面。

这三个阶段,Service Worker 都会触发相应的事件,咱们可以利用这些事件来做一些事情,比如缓存文件、清理旧缓存等。

实战:打造离线新闻网站

光说不练假把式,接下来,咱们就用 Service Worker 来做一个简单的离线新闻网站。别担心,我会一步一步教你,保证你能学会。

1. 准备工作

首先,你需要一个简单的 HTML 页面(index.html),里面包含一些新闻标题和内容。再准备一个 JavaScript 文件(app.js),用来注册 Service Worker。最后,创建一个名为 service-worker.js 的文件,这就是咱们的 Service Worker 脚本。

index.html:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>离线新闻</title>
  <link rel="manifest" href="/manifest.json">
</head>
<body>
  <h1>今日新闻</h1>
  <ul>
    <li>
      <h2>新闻标题1</h2>
      <p>新闻内容1...</p>
    </li>
    <li>
      <h2>新闻标题2</h2>
      <p>新闻内容2...</p>
    </li>
  </ul>
  <script src="app.js"></script>
</body>
</html>

app.js:

if ('serviceWorker' in navigator) {
  window.addEventListener('load', function() {
    navigator.serviceWorker.register('/service-worker.js')
      .then(function(registration) {
        console.log('Service Worker 注册成功:', registration.scope);
      })
      .catch(function(error) {
        console.log('Service Worker 注册失败:', error);
      });
  });
}

这段代码的意思是,如果浏览器支持 Service Worker,就注册 /service-worker.js 这个文件。

2. 编写 Service Worker 脚本

重头戏来了!咱们要开始编写 service-worker.js 文件,实现离线缓存功能。

const CACHE_NAME = 'my-news-cache-v1';
const urlsToCache = [
  '/',
  '/index.html',
  '/app.js',
  '/style.css', // 如果你有样式文件
  // 其他需要缓存的资源
];

// 安装事件
self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(function(cache) {
        console.log('缓存已打开');
        return cache.addAll(urlsToCache);
      })
  );
});

// 激活事件
self.addEventListener('activate', function(event) {
    //这里一般用来清理旧的缓存,暂时不做处理。
});

// fetch 事件
self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        // 如果缓存中有,就直接返回缓存
        if (response) {
          return response;
        }

        // 如果缓存中没有,就发起网络请求
        return fetch(event.request);
      })
  );
});

这段代码做了几件事:

  • 定义缓存名称和需要缓存的文件列表CACHE_NAME 是缓存的唯一标识,urlsToCache 列出了需要缓存的文件。
  • 监听 install 事件:在 Service Worker 安装时,打开缓存并将文件添加到缓存中。
  • 监听 activate 事件:暂时不做处理。
  • 监听 fetch 事件:这是 Service Worker 的核心!每当网页发起请求时,都会触发这个事件。咱们在这里判断请求的资源是否在缓存中,如果在就直接返回缓存,否则发起网络请求。

3. 运行和测试

现在,你可以用一个简单的 HTTP 服务器(比如 Python 的 http.server)来运行你的网站。打开浏览器,访问你的网站,然后打开开发者工具,看看 Service Worker 是否注册成功。

接下来,你可以尝试断开网络,刷新页面,看看新闻是否还能正常显示。如果一切正常,恭喜你,你已经成功构建了一个离线可用的网站!

###4. 清理旧缓存

随着网站的更新,我们需要清理旧的缓存,以节省用户的存储空间。在activate事件中执行此操作:

self.addEventListener('activate', function(event) {
  const cacheWhitelist = [CACHE_NAME]; // 白名单,保留当前版本的缓存

  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            // 如果缓存名称不在白名单中,就删除它
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});

每次更新 Service Worker 时,记得修改 CACHE_NAME,比如从 v1 改为 v2,这样旧的缓存就会被自动清理。

5. 缓存策略

上面的例子中,咱们使用了最简单的“Cache First”(缓存优先)策略。除了这种策略,还有其他几种常用的缓存策略:

  • Network First(网络优先):先尝试从网络获取,如果失败再从缓存中获取。
  • Cache Only(仅缓存):只从缓存中获取,如果缓存中没有就直接返回失败。
  • Network Only(仅网络):只从网络获取,不使用缓存。
  • Stale-While-Revalidate(后台更新):先返回缓存中的内容,同时在后台发起网络请求更新缓存。这种策略可以保证速度,但可能会显示旧的内容。

你可以根据你的网站需求,选择合适的缓存策略。 比如,对于不经常变化的内容,如图片、样式表等使用缓存优先,对于需要实时更新的内容,比如api数据,使用网络优先。

6. manifest.json

为了让你的网站更像一个 App,你可以添加一个 manifest.json 文件,定义网站的名称、图标、启动方式等。

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

在HTML中引用manifest文件。

<link rel="manifest" href="/manifest.json">

总结

Service Worker 是一个强大的工具,可以帮助我们构建更好的 Web 体验。通过本文的介绍,相信你已经对 Service Worker 有了一定的了解,并掌握了如何构建一个简单的离线网站。当然,Service Worker 的功能远不止这些,还有很多高级用法等待你去探索! 比如结合Cache API可以更精细化地控制缓存。 快去试试吧,让你的网站也能“飞”起来!

点评评价

captcha
健康