使用ServiceWorker强大的缓存能力将网站变为本地应用

木头的喵喵拖孩

持续更新中…

注册 ServiceWorker

将网站根目录下的 serviceWorker.js 文件注册为 ServiceWorker。
尽量保证 serviceWorker.js 文件在网站根目录,这样才能监听整个网站的请求

1
2
3
4
5
6
7
8
9
10
11
12
13
if ("serviceWorker" in navigator) {
// 判断浏览器是否支持ServiceWorker
navigator.serviceWorker
.register("/serviceWorker.js", {
scope: "/", // 作用域,默认为serviceWorker.js文件所在目录,也是serviceWorker.js能够监听请求的目录,不能越级监听
})
.then((registration) => {
console.log("ServiceWorker registration successful");
})
.catch((err) => {
console.warn("ServiceWorker registration failed: ", err);
});
}

编写 ServiceWorker

静态资源一般作为网站的骨架,包括通用的样式、字体、图片等,一般不会有太大变化,所以可以作为长期缓存缓存到本地浏览器。

长期缓存的文件会永久的存在于本地,如果出现了静态资源的更新,可在浏览器中使用 ctrl + F5 组合键来强制清除缓存

缓存静态资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// serviceWorker.js

// 静态缓存库名称
const CACHE_STATIC_NAME = "blog_static_cache";

// 静态资源url数组,存放永久/长久不变的静态资源url
const staticUrls = [
"/index.html", // 永久缓存网站首页
];

self.addEventListener("install", (ev) => {
console.log("ServiceWorker install");
// 添加静态缓存
ev.waitUntil(
caches.open(CACHE_STATIC_NAME).then((cache) => {
return cache.addAll(staticUrls);
})
);
});

self.addEventListener("fetch", (ev) => {
ev.respondWith(
caches.match(ev.request).then((cacheResponse) => {
// 匹配到了缓存就使用缓存
if (cacheResponse) return cacheResponse;
// 没匹配到就直接请求
return fetch(ev.request);
})
);
});

添加动态资源缓存

这里的动态资源特指变化周期很短的资源,但即使是变化很快的动态资源,如果它很大,也会影响到页面的加载速度,
所以可以将动态资源缓存到内存中,自定义一个较短的过期时间,过期后重新缓存。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// serviceWorker.js

// 静态缓存库名称
const CACHE_STATIC_NAME = "blog_static_cache";

// 动态缓存库名称
const CACHE_NAME = "blog_cache";

// 静态资源url数组,存放永久/长久不变的静态资源url
const staticUrls = [
"/index.html", // 永久缓存网站首页
];

// 动态资源url的Map对象,存放内容容易变化的资源url以及上次缓存的时间戳
const dynamicUrls = new Map();

/**
* 判断缓存是否过期
* @param {Request} req // 请求对象
* @param {Object} parameter // 配置对象
* @returns {Promise<Boolean>}
*/
function isCacheExpired(req, parameter = {}) {
let neededParms = Object.assign(
{},
{
timeout: 8 * 3600, // 超时时间,默认8个小时
},
parameter
);

let expired = true;
let prevTimestamp = dynamicUrls.get(req.url);

if (prevTimestamp) {
let currentTimestamp = Date.now();
let flag = currentTimestamp > prevTimestamp + neededParms.timeout * 1000;
expired = flag;
} else {
expired = true;
}
return Promise.resolve(expired);
}

/**
* 判断缓存是否是静态缓存
* @param {string} url 请求的url
* @param {string[]} staticUrls 静态缓存url数组
* @return {Boolean}
*/
function isUrlStaticCache(url, staticUrls) {
let find = staticUrls.find((staticUrl) => {
return encodeURIComponent(url).includes(encodeURIComponent(staticUrl));
});
if (find) return true;
return false;
}

/**
* 判断url是否在当前域
* @param {string} url 请求的url
* @return {Boolean}
*/
function isUrlCurrentOrigin(url) {
return url.includes(self.location.origin);
}

self.addEventListener("install", (ev) => {
console.log("ServiceWorker install");
// 添加静态缓存
ev.waitUntil(
caches.open(CACHE_STATIC_NAME).then((cache) => {
return cache.addAll(staticUrls);
})
);
});

self.addEventListener("fetch", (ev) => {
ev.respondWith(
caches.match(ev.request).then(async (cacheResponse) => {
// 有缓存
if (cacheResponse) {
// 如果缓存是静态缓存,则直接返回
if (isUrlStaticCache(ev.request.url, staticUrls)) return cacheResponse;
// 如果是非静态缓存,则判断是否过期,过期则更新缓存
else {
let expired = await isCacheExpired(ev.request);
if (expired) {
// 更新缓存
let response = await fetch(ev.request);
const responseClone = response.clone();
let cache = await caches.open(CACHE_NAME);
cache.put(ev.request, responseClone);
dynamicUrls.set(ev.request.url, Date.now());
return response;
} else {
return cacheResponse;
}
}
}

// 没有缓存
else {
if (isUrlCurrentOrigin(ev.request.url)) {
// 添加缓存
let response = await fetch(ev.request);
const responseClone = response.clone();
let cache = await caches.open(CACHE_NAME);
cache.put(ev.request, responseClone);
dynamicUrls.set(ev.request.url, Date.now());
return response;
} else {
return fetch(ev.request);
}
}
})
);
});
  • 标题: 使用ServiceWorker强大的缓存能力将网站变为本地应用
  • 作者: 木头的喵喵拖孩
  • 创建于: 2024-02-29 10:24:06
  • 更新于: 2024-05-21 10:56:15
  • 链接: https://blog.xx-xx.top/2024/02/29/使用ServiceWorker强大的缓存能力将网站变为本地应用/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
此页目录
使用ServiceWorker强大的缓存能力将网站变为本地应用