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,现在只要用户访问过一次我的网站,第二次访问时即使没网络也可以访问我的页面了

因为所有文件都被缓存了

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

相关推荐
繁依Fanyi5 分钟前
ImgShrink:摄影暗房里的在线图片压缩工具开发记
开发语言·前端·codebuddy首席试玩官
卓律涤10 分钟前
【找工作系列①】【大四毕业】【复习】巩固JavaScript,了解ES6。
开发语言·前端·javascript·笔记·程序人生·职场和发展·es6
Ten peaches1 小时前
Selenium-Java版(环境安装)
java·前端·selenium·自动化
心.c1 小时前
vue3大事件项目
前端·javascript·vue.js
姜 萌@cnblogs1 小时前
【实战】深入浅出 Rust 并发:RwLock 与 Mutex 在 Tauri 项目中的实践
前端·ai·rust·tauri
蓝天白云下遛狗1 小时前
google-Chrome常用插件
前端·chrome
多多*2 小时前
Spring之Bean的初始化 Bean的生命周期 全站式解析
java·开发语言·前端·数据库·后端·spring·servlet
linweidong2 小时前
在企业级应用中,你如何构建一个全面的前端测试策略,包括单元测试、集成测试、端到端测试
前端·selenium·单元测试·集成测试·前端面试·mocha·前端面经
满怀10152 小时前
【HTML 全栈进阶】从语义化到现代 Web 开发实战
前端·html
东锋1.32 小时前
前端动画库 Anime.js 的V4 版本,兼容 Vue、React
前端·javascript·vue.js