-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsw-study.js
279 lines (232 loc) · 6.94 KB
/
sw-study.js
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
'use strict';
const version = 'lzwme_201703231500';
const __DEVELOPMENT__ = false;
const __DEBUG__ = true;
const offlineResources = [
'/',
'/offline.html',
'/wp-content/themes/Kratos/images/default.jpg'
];
const ignoreCache = [
/https?:\/\/hm.baidu.com\//,
/https?:\/\/cdn.bootcss.com\//,
/https?:\/\/static.duoshuo.com\//,
/https?:\/\/www.google-analytics.com\//,
/https?:\/\/dn-lbstatics.qbox.me\//,
/https?:\/\/ajax.cloudflare.com\//,
/https?:\/\/cdn1.lncld.net\//,
/https?:\/\/api.leancloud.cn\//,
/https?:\/\/lzw.me\/wp\-admin/,
];
// 慎重使用全局可变变量,因为 serviceWork 不可控的停止和重启,会导致它们的取值在后续读取时无法预测
let port;
/**
* common function
*/
function developmentMode() {
return __DEVELOPMENT__ || __DEBUG__;
}
function cacheKey() {
return [version, ...arguments].join(':');
}
function log() {
if (developmentMode()) {
console.log("SW:", ...arguments);
}
}
// 不需要缓存的请求
function shouldAlwaysFetch(request) {
return __DEVELOPMENT__ ||
request.method !== 'GET' ||
ignoreCache.some(regex => request.url.match(regex));
}
// 缓存 html 页面
function shouldFetchAndCache(request) {
return (/text\/html/i).test(request.headers.get('Accept'));
}
// 发送 Notification 通知
function sendNotify(title, options, event) {
if (Notification.permission !== 'granted') {
log('Not granted Notification permission.');
// 无授权时,向来源页面申请授权
if (port && port.postMessage) {
port.postMessage({
type: 'applyNotify',
info: {title, options}
});
}
return;
}
const notificationPromise = self.registration.showNotification(title || 'Hi:', Object.assign({
body: '这是一个通知示例',
icon: '//lzw.me/images/avatar/lzwme-80x80.png',
tag: 'push'
}, options));
return event && event.waitUntil(notificationPromise);
}
/**
* onClickNotify
*/
function onClickNotify(event) {
event.notification.close();
const url = "https://lzw.me";
event.waitUntil(
self.clients.matchAll({
type: "window"
})
.then(() => {
if (self.clients.openWindow) {
return self.clients.openWindow(url);
}
})
);
}
/**
* Install 安装
*/
function onInstall(event) {
log('install event in progress.');
event.waitUntil(
caches.open(cacheKey('offline'))
.then(cache => cache.addAll(offlineResources))
.then(() => log('installation complete! version: ' + version))
.then(() => self.skipWaiting())
);
}
/**
* Fetch
*/
// 当网络离线或请求发生了错误,使用离线资源替代 request 请求
function offlineResponse(request) {
log('(offline)', request.method, request.url);
if (request.url.match(/\.(jpg|png|gif|svg|jpeg)(\?.*)?$/)) {
return caches.match('/wp-content/themes/Kratos/images/default.jpg');
} else {
return caches.match('/offline.html');
}
}
// 从缓存读取或使用离线资源替代
function cachedOrOffline(request) {
return caches
.match(request)
.then((response) => response || offlineResponse(request));
}
// 从网络请求,并将请求成功的资源缓存
function networkedAndCache(request) {
return fetch(request)
.then(response => {
const copy = response.clone();
caches.open(cacheKey('resources'))
.then(cache => {
cache.put(request, copy);
});
log("(network: cache write)", request.method, request.url);
return response;
});
}
// 优先从 cache 读取,读取失败则从网络请求并缓存。网络请求也失败,则使用离线资源替代
function cachedOrNetworked(request) {
return caches.match(request)
.then((response) => {
log(response ? '(cached)' : '(network: cache miss)', request.method, request.url);
return response ||
networkedAndCache(request)
.catch(() => offlineResponse(request));
});
}
// 优先从网络请求,失败则使用离线资源替代
function networkedOrOffline(request) {
return fetch(request)
.then(response => {
log('(network)', request.method, request.url);
return response;
})
.catch(() => offlineResponse(request));
}
function onFetch(event) {
const request = event.request;
// 应当永远从网络请求的资源
// 如果请求失败,则使用离线资源替代
if (shouldAlwaysFetch(request)) {
log('AlwaysFetch request: ', event.request.url);
event.respondWith(networkedOrOffline(request));
return;
}
// 应当从网络请求并缓存的资源
// 如果请求失败,则尝试从缓存读取,读取失败则使用离线资源替代
if (shouldFetchAndCache(request)) {
event.respondWith(
networkedAndCache(request).catch(() => cachedOrOffline(request))
);
return;
}
event.respondWith(cachedOrNetworked(request));
}
/**
* Activate
*/
function removeOldCache() {
return caches
.keys()
.then(keys =>
Promise.all( // 等待所有旧的资源都清理完成
keys
.filter(key => !key.startsWith(version)) // 过滤不需要删除的资源
.map(key => caches.delete(key)) // 删除旧版本资源,返回为 Promise 对象
)
)
.then(() => {
log('removeOldCache completed.');
});
}
function onActivate(event) {
log('activate event in progress.');
event.waitUntil(Promise.all([
// 更新客户端
self.clients.claim(),
removeOldCache()
]))
}
/**
* onPush
*/
function onPush(event) {
log('onPush ', event);
sendNotify('Hi:', {
body: `【${new Date()}】发生了一次 Push 同步事件 ~`
}, event);
}
/**
* onSync
*/
function onSync(event) {
log('onSync', event);
sendNotify('Hi:', {
body: `【${new Date()}】发生了一次 Sync 同步事件 ~`
}, event);
}
/**
* onMessage
*/
function onMessage(event) {
log('onMessage', event);
if (event.ports) {
port = event.ports[0];
}
if (!event.data) {
return;
}
// 如果是要求一条通知,则发送
if (event.data.type === 'notify') {
const {title, options} = event.data.info || {};
sendNotify(title, options, event);
}
}
log("Hello from ServiceWorker land!", version);
self.addEventListener('install', onInstall);
self.addEventListener('fetch', onFetch);
self.addEventListener("activate", onActivate);
self.addEventListener("push", onPush);
self.addEventListener("sync", onSync);
self.addEventListener('message', onMessage);
self.addEventListener("notificationclick", onClickNotify);