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

因为所有文件都被缓存了

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

相关推荐
diemeng11199 分钟前
2024系统编程语言风云变幻:Rust持续领跑,Zig与Ada异军突起
开发语言·前端·后端·rust
烂蜻蜓11 分钟前
Uniapp 中布局魔法:display 属性
前端·javascript·css·vue.js·uni-app·html
java1234_小锋41 分钟前
一周学会Flask3 Python Web开发-redirect重定向
前端·python·flask·flask3
琑951 小时前
nextjs项目搭建——头部导航
开发语言·前端·javascript
light多学一点1 小时前
视频的分片上传
前端
Gazer_S2 小时前
【Windows系统node_modules删除失败(EPERM)问题解析与应对方案】
前端·javascript·windows
bigyoung2 小时前
基于 React 的列表实现方案,包含创建和编辑状态,使用 Modal 弹框和表单的最佳实践
前端
乌木前端2 小时前
包管理工具lock文件的作用
前端·javascript
司玄2 小时前
3dtiles平移旋转原理及可视化工具实现
前端
m0_748236582 小时前
本地部署轻量级web开发框架Flask并实现无公网ip远程访问开发界面
前端·tcp/ip·flask