JS 缓存: Service Worker 实现离线应用

文章目录

  • JS 缓存: Service Worker 实现离线应用
  • Service Worker 概述
  • 1. 加载 Service Worker
  • 2. Service Worker 编程
    • 2.0 Service Worker 生命周期
    • 2.1 install 启用缓存
    • 2.2 fetch 缓存代理
    • 2.3 activate 清理资源
  • 小结
  • 其他资源
    • 参考连接
    • 完整代码示例

Service Worker 概述

Service Worker 属于一种特殊的 Web Worker 之一,有兴趣可以参考前篇:HTML5 新特性: Web Worker 的创建与使用(webpack + TS 环境)

今天要介绍的 Service Worker 的一个主要功能就是在于缓存整个应用,使我们能够在离线状态下也能使用已经访问过的应用

1. 加载 Service Worker

在开始具体的进行 Service Worker 编程之前,我们先来看看如何加载一个 Service Worker

  • index.js
const INDEX_PREFIX = `[index.js]`;console.log(`${INDEX_PREFIX} load script sucess`);// load service worker
if ('serviceWorker' in navigator) {window.addEventListener('load', () => {const serviceWorkerUrl = '/sw.js';console.log(`${INDEX_PREFIX} try register serviceWorker: ${serviceWorkerUrl}`);navigator.serviceWorker.register(serviceWorkerUrl).then((registration) => {console.log(`${INDEX_PREFIX} register success:`, registration);}).catch((reason) => {console.log(`${INDEX_PREFIX} register fail:`, reason);});});
}

加载一个 Service Worker 的关键点在 navigator.serviceWorker 指向的 ServiceWorkerContainer 对象上,然后我们使用 ServiceWorkerContainer.prototype.register(path) 进行注册。

注意这里传入的 path 是 Service Worker 的脚本路径,同时必须是同源的(关于 scope 这里就不扯了)

接下来则是写一个 Service Worker 用的脚本就行了

  • sw.js
const CURRENT_VERSION = 'v1';
const LIFECYCLE_PREFIX = `[serviceWorker: sw.js(${CURRENT_VERSION})]`;console.log(`${LIFECYCLE_PREFIX} load serviceWorker`, this);

从上面我们就可以看到一个 Service Worker 被加载进来了

同时我们也可以从下面两种方式查看当前 Service Worker 的运行情况

  • 从控制台 F12 Application > Application > Service Workers 下查看当前页面的 Service Worker

    • Service Worker 的注册是与域名相关的,因此我们在这里通常是查看当前域名下的所有 Service Worker

  • 从 Chrome 浏览器下的 inspect 页面查看所有 Service Worker

    • chrome://inspect/#service-workers

2. Service Worker 编程

接下来我们进入主要的 Service Worker 编程

2.0 Service Worker 生命周期

首先我们先来看 Service Worker 的生命周期

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MwAMwL0c-1641360030839)(https://developers.google.com/web/fundamentals/primers/service-workers/images/sw-lifecycle.png?hl=zh-cn)]

  • 参考 Google 提供的 Service Worker 简介

实际上 Service Worker 属于一段运行在一个独立进程的上下文环境当中,因此即使我们关闭应用页面还是会独立存在。这时候如果我们重新打开页面,Service Worker 就能够监听到一些特殊的事件(如 install、fetch 等),然后进而对部分页面资源进行代理、缓存的作用。

不仅仅是在离线状态下能提供一定程度的页面保留,在正常连线的情况也能提供部分的页面缓存加速功能

2.1 install 启用缓存

我们要介绍的第一个事件是 install 事件,也就是 Service Worker 第一次启用的时候会调用的方法

  • sw.js
self.addEventListener('install', (event) => {console.log(`${LIFECYCLE_PREFIX} onInstall`, event);event.waitUntil(caches.open(CURRENT_VERSION).then((cache) => {return cache.addAll(['/', '/index.html', '/index.css', '/index.js']);}));
});

在 install 钩子下,我们使用 caches.open + cache.addAll 来声明我们需要缓存的资源路径,结果如下图

2.2 fetch 缓存代理

在 install 钩子声明好 cache 的缓存资源之后,我们可以透过监听 fetch 事件来拦截页面的资源请求,然后透过返回缓存结果来进行加速/置换

  • sw.js
self.addEventListener('fetch', (event) => {console.log(`${LIFECYCLE_PREFIX} onFetch, url=${event.request.url}`, event);event.respondWith(caches.match(event.request).then((response) => {if (response) {console.log(`${LIFECYCLE_PREFIX} onFetch: pre cache`, response);}return (response ||fetch(event.request).then(function (response) {let responseClone = response.clone();console.log(`${LIFECYCLE_PREFIX} onFetch: fetch and cache`, response);caches.open(CURRENT_VERSION).then(function (cache) {cache.put(event.request, responseClone);});return response;}).catch(function () {// return caches.match('/sw-test/gallery/myLittleVader.jpg');return new Response('fetch fail');}));}));
});

我们监听到 fetch 事件之后,判断是否经过缓存(caches.match),决定是否使用 fetch(event.request) 方法重新发起请求,并且使用 cache.push 写入缓存当中,最后返回请求

2.3 activate 清理资源

到此为止整个 Service Worker 应该都能够正常运行了,最后我们考虑一个场景:当我们的应用进行更新之后,页面的缓存应该需要适当地刷新(也就是 CURRENT_VERSION 对应的版本号应该进行变化,也就是同时修改作为缓存 key 的吧版本号,因此我们需要透过监听 activate 事件来进行缓存资源的清理)

  • sw.js
self.addEventListener('activate', (event) => {console.log(`${LIFECYCLE_PREFIX} onActivate`, event);// clean none current version cacheevent.waitUntil(caches.keys().then((keys) => {console.log(`${LIFECYCLE_PREFIX} onActivate: caches keys`, keys);return Promise.all(keys.map((key) => {if (key !== CURRENT_VERSION) {return caches.delete(key);}}));}));
});

每次 Service Worker 重新启动的时候,我们去检查是否存在其他版本的缓存记录,并进行资源清理的工作

这里关于为什么是在 activate 事件内进行清除,这里我理解的是因为每次加载新版本的 Service Worker 会进行一次新的 Install 事件,然而过程对于 fetch 资源的管理不一定成功,也就是说可以在此阶段进行版本回退/兼容等操作。

因此我们必须等到下一次 Service Worker 再加载,同时没有更新(现有版本 Service Worker 重新启动)的状态下,可以看做当前 Service Worker 的版本已经趋于稳定,才对先前的缓存资源进行清理

小结

Service Worker 不同于通用的 Web Worker,主要关注点在于页面资源的管理,当然或许还有其他的应用方式,欢迎读者与作者分享。

其他资源

参考连接

Title Link
Service Worker API - MDN https://developer.mozilla.org/zh-CN/docs/Web/API/Service_Worker_API
使用 Service Workers - MDN https://developer.mozilla.org/zh-CN/docs/Web/API/Service_Worker_API/Using_Service_Workers
Service Worker: 简介 - Web Fundamentals https://developers.google.com/web/fundamentals/primers/service-workers?hl=zh-cn

完整代码示例

https://github.com/superfreeeee/Blog-code/tree/main/front_end/javascript/js_service_worker

JS 缓存: Service Worker 实现离线应用相关推荐

  1. Service Worker 概念简介

    原文 丰富的离线体验.定期后台同步.推送通知--通常需要原生应用程序的功能--正在网络上出现. Service Worker 提供了所有这些功能所依赖的技术基础. What is a service ...

  2. Service Worker的应用

    Service Worker的应用 Service worker本质上充当Web应用程序.浏览器与网络(可用时)之间的代理服务器,这个API旨在创建有效的离线体验,它会拦截网络请求并根据网络是否可用来 ...

  3. 聊聊Service Worker

    Web Workers web worker: 为Web内容在后台线程中运行脚本提供了一种简单的方法,线程可以执行任务而不干扰用户界面,即:运行在后台的 JavaScript 浏览器一般有三类 web ...

  4. 借助Service Worker和cacheStorage缓存及离线开发

    一.缓存和离线开发 说得HTML5离线开发,我们通常第一反应是使用html5 manifest缓存技术,此技术已经出现很多年了,我以前多次了解过,也见过一些实践案例,但是却从未在博客中介绍过,因为并不 ...

  5. Service Worker 离线无法缓存Post请求的问题解决

    Service Worker 离线无法缓存Post请求的问题解决 参考文章: (1)Service Worker 离线无法缓存Post请求的问题解决 (2)https://www.cnblogs.co ...

  6. 【转载】古典浏览器缓存和Service Worker对比

    1. 传统的HTTP浏览器缓存策略 在一个网页的生命周期中,开发者为了缩短用户打开页面的时间,通常会设置很多缓存.其中包括了: 浏览器缓存 代理服务器缓存(CDN缓存) 服务器缓存 数据库缓存 等各种 ...

  7. 缓存存在那些位置?缓存位置可分Service Worker、Memory Cache、Disk Cache、Push Cache四种

    从缓存位置上来说分为四种,并且各自有优先级,当依次查找缓存且都没有命中的时候,才会去请求网络. Service Worker Memory Cache Disk Cache Push Cache Se ...

  8. PWA 应用 Service Worker 缓存的一些可选策略和使用场景

    SAP 电商云 Spartacus UI 提供了将站点作为 PWA 运行的功能. 这提高了用户性能,改善了用户体验,因为它添加了另一个缓存层,并减少了服务器端渲染 (SSR) 服务的负载. PWA 的 ...

  9. Service Worker

    Service Worker 随着前端快速发展,应用的性能已经变得至关重要,关于这一点大佬做了很多统计.你可以去看看. 如何降低一个页面的网络请求成本从而缩短页面加载资源的时间并降低用户可感知的延时是 ...

  10. 初识Service Worker

    当下PWA比较火,而Service Worker是实现PWA的一项关键技术,今天我们一起了解下关于Service Worker的一些基础知识和适用场景. 什么是Server Worker 我们先来看一 ...

最新文章

  1. 利用XRDP远程登陆linux系统
  2. 【学术研究基础】聚类分析学习
  3. 第十一届青少年蓝桥杯国赛真题精选 - 编程题
  4. 修改httpd默认端口号
  5. 教师排课程序设计c语言,计算中心
  6. 分布式mysql 不支持存储过程_分布式数据库VoltDB对存储过程的支持
  7. 类似Jira的十大项目管理软件
  8. 各大网站收录、搜索引擎的提交入口
  9. 【墨墨英语单词库免费开源无偿分享】小学、初中、高中、大学四六级专四专八、考研、托福、雅思等词书文本大合集
  10. 小白如何通俗地理解 - - 遗传算法以及其实际应用?
  11. 基于R语言的Kaggle案例分析学习笔记(七)
  12. 精通 Python OpenCV4:第二部分
  13. [效率提升]webstorm配置Prettier
  14. 2019中国脑科学与神经调控技术发展高峰论坛
  15. 梅科尔工作室-李柯增-鸿蒙笔记2
  16. Kotlin 旅途篇(一)
  17. 开源免费的对象存储Minio
  18. k8s pod重启前的日志查看
  19. 1、输入圆柱体底面积的半径和圆柱体的高,输出其体积。
  20. 创建空白文档失败的原因

热门文章

  1. Nodejs ORM Prisma 介绍
  2. 斗圣苍穹游戏代码(点关注,不迷路,还有更多c++小程序等着你)
  3. 微信开发者工具使用git
  4. 【树莓派】从零搭建DAS服务器,挂载扩容硬盘,实现文件存储与自动下载
  5. dojo query 实现Ajax,Dojo Query 详解
  6. java生成eml_用Java创建一个.eml(email)文件
  7. IntelliJ Idea快捷键(排版清晰!!持续更新!!非常详细)
  8. html数独游戏制作,使用HTML5和ES6(JS)实现的在线数独游戏生成器和解答
  9. 图论-生成树-黑暗城堡
  10. 48.XML保存衣服尺码信息