你网站的网速是很快,但是在没有网络的情况下你怎么办?🐒🐒🐒

在现代的网络世界里,5G 网络的普及,我们可以访问一个网站或者使用一个 App 的速度极其快,但是在没有网络的情况下你啥都看不了,只能大眼瞪小眼了。

离线应用是指通过离线缓存技术,让资源在第一次被加载后缓存在本地,下次访问它时就直接返回本地的文件,就算没有网络连接。

通过离线应用,主要有以下几个优点:

  1. 在没有网络的情况下也能打开网页。
  2. 由于部分被缓存的资源直接从本地加载,对用户来说可以加速网页加载速度,对网站运营者来说可以减少服务器压力以及传输流量费用。

离线应用的核心是离线缓存技术,要实现这种方式,我们可以使用 Service Worker 来实现这种缓存技术。

什么是 Service Worker

Service Worker 服务器和浏览器之间的之间的桥梁或者中间人。

Service Worker 运行在一个与页面 JavaScript 主线程独立的线程上,并且无权访问 DOM 结构。但是它能拦截当前网站所有的请求,对请求使用相应的逻辑进行判断,如果需要向服务器发起请求的就转给服务器,如果可以直接使用缓存的就直接返回缓存不再转给服务器。从而大大提高浏览体验。

注册 Service Worker

要使用 Service Worker,首先我们要判断浏览器是否支持 Service Worker,具体代码逻辑如下:

js 复制代码
if (navigator.serviceWorker) {
  window.addEventListener("DOMContentLoaded", function () {
    navigator.serviceWorker.register("/worker.js");
  });
}

这段代码的主要目的是在支持 Service Worker 的浏览器中,当页面加载完成后注册一个指定的 Service Worker 脚本。这个传入的 worker.js 就是 Service Worker 的运行环境。

这个脚本被安装到浏览器中后,就算用户关闭了当前网页,它仍会存在。 也就是说第一次打开该网页时 Service Workers 的逻辑不会生效,因为脚本还没有被加载和注册,但是以后再次打开该网页时脚本里的逻辑将会生效。

Service Worker 安装和激活

注册完成后,worker.js 文件会自动下载、安装,然后激活。它提供了一些 API 给我们做一些监听事件:

js 复制代码
self.addEventListener("install", function (e) {
  console.log("Service Worker 安装成功");
});

self.addEventListener("fetch", function (event) {
  console.log("service worker is fetch");
});

当 install 完成并且成功激活之后,就能够监听 fetch 操作了,如上代码所示,输出结构如下图所示:

使用 Service Workers 实现离线缓存

在上面的内容我们已经知道了 Service Workers 在注册成功后会在其生命周期中派发出一些事件,通过监听对应的事件在特点的时间节点上做一些事情。

在 Service Workers 安装成功后会派发出 install 事件,需要在这个事件中执行缓存资源的逻辑,实现代码如下:

js 复制代码
// 当前缓存版本的唯一标识符,用当前时间代替
const cacheKey = new Date().toISOString();

// 需要被缓存的文件的 URL 列表
const cacheFileList = ["/index.html", "/index.js", "/index.css"];

// 监听 install 事件
self.addEventListener("install", function (event) {
  // 等待所有资源缓存完成时,才可以进行下一步
  event.waitUntil(
    caches.open(cacheKey).then(function (cache) {
      // 要缓存的文件 URL 列表
      return cache.addAll(cacheFileList);
    })
  );
});

在 install 阶段我们就已经指定了要被缓存的内容了,那么就可以在 fetch 阶段中听网络请求事件去拦截请求,复用缓存,代码如下:

js 复制代码
self.addEventListener("fetch", function (event) {
  event.respondWith(
    // 去缓存中查询对应的请求
    caches.match(event.request).then(function (response) {
      // 如果命中本地缓存,就直接返回本地的资源
      if (response) {
        return response;
      }
      // 否则就去用 fetch 下载资源
      return fetch(event.request);
    })
  );
});

通过上面的操作,创建和添加了一个缓存的库,如下图所示:

缓存更新

线上的代码有时需要更新和重新发布,如果这个文件被离线缓存了,那就需要 Service Workers 脚本中有对应的逻辑去更新缓存。

这可以通过更新 Service Workers 脚本文件做到,浏览器针对 Service Worker 有如下机制:

  1. 每次打开接入了 Service Workers 的网页时,浏览器都会去重新下载 Service Workers 脚本文件,如果发现和当前已经注册过的文件存在字节差异,就将其视为新服务工作线程。
  2. 新 Service Workers 线程将会启动,且将会触发其 install 事件。
  3. 当网站上当前打开的页面关闭时,旧 Service Workers 线程将会被终止,新 Service Workers 线程将会取得控制权。
  4. 新 Service Workers 线程取得控制权后,将会触发其 activate 事件。

新 Service Workers 线程中的 activate 事件就是最佳的清理旧缓存的时间点,代码如下:

js 复制代码
var cacheWhitelist = [cacheKey];

self.addEventListener("activate", function (event) {
  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 作为服务器和浏览器两者之间的桥梁,它并且可以缓存技术,通过这种方式,在断网的时候,去获取缓存中相应的数据以展示给客户显示。

当断网之后,直接给他页面返回一个俄罗斯方块让他玩足一整天。

相关推荐
Y学院2 分钟前
vue的组件通信
前端·javascript·vue.js
患得患失9493 分钟前
【ThreeJs】【伪VR】用 Three.js 实现伪 VR 全景看房系统:低成本实现 3D 级交互体验
javascript·3d·vr
PairsNightRain5 分钟前
React Concurrent Mode 是什么?怎么使用?
前端·react.js·前端框架
小岛前端19 分钟前
React 剧变!
前端·react.js·前端框架
UrbanJazzerati29 分钟前
一文带你了解定语
面试
teeeeeeemo30 分钟前
Webpack 模块联邦(Module Federation)
开发语言·前端·javascript·笔记·webpack·node.js
UrbanJazzerati1 小时前
一文带你了解同位语
面试
岁月宁静1 小时前
AI聊天系统 实战:打造优雅的聊天记录复制与批量下载功能
前端·vue.js·人工智能
小小弯_Shelby1 小时前
uniApp App内嵌H5打开内部链接,返回手势(左滑右滑页面)会直接关闭H5项目
前端·uni-app
IT_陈寒1 小时前
SpringBoot性能飞跃:5个关键优化让你的应用吞吐量提升300%
前端·人工智能·后端