Service Worker 实现网站可离线访问

Service Worker 生命周期

Service Worker 的生命周期包括以下几个阶段:

  • 注册
  • 安装
  • 等待
  • 激活
  • 终止

在等待阶段,新的 Service Worker 需要等待所有控制它的页面(也就是使用它的页面)都被关闭后才能进入激活阶段。这是因为如果在一个页面还在使用旧的 Service Worker 的时候就激活新的 Service Worker,可能会导致问题。

例如,新的 Service Worker 可能会使用一个新的缓存策略,而这个页面可能还在使用旧的缓存策略,这可能会导致缓存的不一致。

等待所有页面都被关闭可以确保在新的 Service Worker 激活时,没有页面还在使用旧的 Service Worker。这样,我们就可以在新的 Service Worker 中自由地更新我们的缓存策略,而不需要担心会影响到正在使用旧的 Service Worker 的页面。

如果你希望新的 Service Worker 在安装完成后立即激活,无需等待所有页面都被关闭,你可以在你的 Service Worker 脚本中调用 self.skipWaiting() 方法。但是,请注意这可能会导致上述的问题。

创建 sw.js

Service Worker 只能控制其所在目录及其子目录下的文件。

例如,如果你将 sw.js 放在 /scripts/ 目录下,那么这个 Service Worker 只能控制 /scripts/ 目录及其子目录下的文件,不能控制其他目录下的文件。

所以如果你希望你的 Service Worker 能控制你的整个站点,那么你应该将其放在项目的根目录

先在 public 目录下创建 sw.js

js 复制代码
const CACHE_NAME = "my-cache-v1";
const defaultCacheUrl = ['/background.webp'];

// 当 Service Worker 被首次注册或者更新时,install 事件会被触发。
self.addEventListener("install", function (event) {
  event.waitUntil(
    caches.open(CACHE_NAME).then(function (cache) {
      console.log("Opened cache");
      return cache.addAll(urlsToCache);
    })
  );
});

// Service Worker 被激活时会触发
self.addEventListener("activate", function (event) {
  var 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

在main.js中写上 Service Worker 注册代码

js 复制代码
// main.js
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js').then(function(registration) {
    console.log('Service Worker registered with scope:', registration.scope);
  }).catch(function(error) {
    console.log('Service Worker registration failed:', error);
  });
}

缓存策略

  1. Stale while revalidate:这种策略首先从缓存中获取响应并立即返回,然后在后台从网络获取响应并更新缓存。这种策略适用于可以容忍短暂过期的资源。
  2. Network first, then cache:这种策略首先尝试从网络获取响应,如果网络请求失败,那么它会从缓存中获取响应。这种策略适用于需要实时数据的应用。
  3. Cache first, then network:这种策略首先尝试从缓存中获取响应,如果缓存中没有找到响应,那么它会从网络获取响应。这种策略适用于静态资源,如 CSS 和 JavaScript 文件。

Stale while revalidate

js 复制代码
// 直接从缓存中取,同时会发起网络请求 更新本地缓存,这意味着资源不会立即更新,而是会在发起第二次请求后才是最新的
self.addEventListener("fetch", function (event) {
  event.respondWith(
    caches.open(CACHE_NAME).then(function (cache) {
      return cache.match(event.request).then(function (response) {
        const fetchPromise = fetch(event.request).then(function (networkResponse) {
          cache.put(event.request, networkResponse.clone());
          return networkResponse;
        });

        return response || fetchPromise;
      });
    })
  );
});

ok,现在只要用户访问过一次我的网站,第二次访问时即使没网络也可以访问我的页面了

因为所有文件都被缓存了

上面只实现了一种缓存策略,另外两种后面更新!

相关推荐
子兮曰1 分钟前
深入理解滑块验证码:那些你不知道的防破解机制
前端·javascript·canvas
会一丢丢蝶泳的咻狗27 分钟前
Sass实现,蛇形流动布局
前端·css
攀登的牵牛花32 分钟前
前端向架构突围系列 - 状态数据设计 [8 - 4]:有限状态机 (FSM) 在复杂前端逻辑中的应用
前端
Lsx_32 分钟前
前端视角下认识 AI Agent 和 LangChain
前端·人工智能·agent
我是伪码农1 小时前
Vue 智慧商城项目
前端·javascript·vue.js
不认输的西瓜1 小时前
fetch-event-source源码解读
前端·javascript
用户39051332192881 小时前
前端性能杀手竟然不是JS?图片优化才是绝大多数人忽略的"降本增效"方案
前端
朱昆鹏2 小时前
开源 Claude Code + Codex + 面板 的未来vibecoding平台
前端·后端·github
lyrieek2 小时前
pgadmin的导出图实现,还在搞先美容后拍照再恢复?
前端
永远是我的最爱2 小时前
基于.NET的小小便利店前台收银系统
前端·sqlserver·.net·visual studio