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

因为所有文件都被缓存了

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

相关推荐
特别橙的橙汁几秒前
Node.js 调用可执行文件时的 stdout 缓冲区问题
前端·node.js·swift
yiranlater几秒前
点云八叉树处理
前端
榴莲CC6 分钟前
VK1620 抗噪数显LED驱动芯片数码管显示IC内置 RC振荡器/8级整体亮度可调
前端
@Autowire10 分钟前
Layout-box-sizing是 CSS 中控制元素盒模型计算方式的核心属性,直接决定了元素的 width/height 是否包含内边距和边框
前端
alamhubb11 分钟前
反感pnpm的全链路污染?可以了解下这个对原项目零侵入,零修改完全兼容npm的monorepo工具
前端·javascript·node.js
叁两12 分钟前
“死了么”用户数翻800倍,估值近1亿,那我来做个“活着呢”!
前端·人工智能·产品
AdleyTales40 分钟前
vscode识别不了@提示找不到路径解决
前端·javascript·vscode
去哪儿技术沙龙1 小时前
去哪儿网前端代码自动生成技术实践
前端·ai编程
前端九哥1 小时前
装个依赖把公司电脑干报废了?npm i 到底背着我干了啥?
前端·javascript
溪海莘1 小时前
React入门:跟读官方快速入门教程(前端小白)
前端·react.js·前端框架