-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsw.js
136 lines (123 loc) · 3.79 KB
/
sw.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
const cdn = {
gh: {
jsdelivr: 'https://cdn.jsdelivr.net/gh',
fastly: 'https://fastly.jsdelivr.net/gh',
gcore: 'https://gcore.jsdelivr.net/gh',
testingcf: 'https://testingcf.jsdelivr.net/gh',
test1: 'https://test1.jsdelivr.net/gh',
tianli: 'https://cdn1.tianli0.top/gh'
},
combine: {
jsdelivr: 'https://cdn.jsdelivr.net/combine',
fastly: 'https://fastly.jsdelivr.net/combine',
gcore: 'https://gcore.jsdelivr.net/combine',
testingcf: 'https://testingcf.jsdelivr.net/combine',
test1: 'https://test1.jsdelivr.net/combine',
tianli: 'https://cdn1.tianli0.top/combine'
},
npm: {
jsdelivr: 'https://cdn.jsdelivr.net/npm',
fastly: 'https://fastly.jsdelivr.net/npm',
gcore: 'https://gcore.jsdelivr.net/npm',
testingcf: 'https://testingcf.jsdelivr.net/npm',
test1: 'https://test1.jsdelivr.net/npm',
eleme: 'https://npm.elemecdn.com',
unpkg: 'https://unpkg.com',
tianli: 'https://cdn1.tianli0.top/npm'
}
}
self.addEventListener('install', async () => {
await self.skipWaiting()
})
self.addEventListener('activate', async () => {
await self.clients.claim()
})
self.addEventListener('fetch', async (event) => {
try {
// 如果用户当前网速慢,或是开启了省流模式,则不使用sw处理请求
const nav = navigator
const { saveData, effectiveType } = nav.connection || nav.mozConnection || nav.webkitConnection || {}
if (saveData || /2g/.test(effectiveType)) return
// 劫持请求
event.respondWith(handleRequest(event.request))
// eslint-disable-next-line
} catch (e) {}
})
// 返回响应
async function progress(res) {
return new Response(await res.arrayBuffer(), {
status: res.status,
headers: res.headers
})
}
function handleRequest(req) {
const urls = []
const urlStr = req.url
let urlObj = new URL(urlStr)
// 为了获取 cdn 类型
// 例如获取gh (https://cdn.jsdelivr.net/gh)
const path = urlObj.pathname.split('/')[1]
// 匹配 cdn
for (const type in cdn) {
if (type === path) {
for (const key in cdn[type]) {
const url = cdn[type][key] + urlObj.pathname.replace('/' + path, '')
urls.push(url)
}
}
}
// 如果上方 cdn 遍历 匹配到 cdn 则直接统一发送请求
if (urls.length) return fetchAny(urls)
throw new Error('failure')
}
// Promise.any 的 polyfill
function createPromiseAny() {
Promise.any = function (promises) {
return new Promise((resolve, reject) => {
promises = Array.isArray(promises) ? promises : []
let len = promises.length
let errs = []
if (len === 0) return reject(new AggregateError('All promises were rejected'))
promises.forEach((p) => {
if (p instanceof Promise) {
p.then(
(res) => resolve(res),
(err) => {
len--
errs.push(err)
if (len === 0) reject(new AggregateError(errs))
}
)
} else {
reject(p)
}
})
})
}
}
// 发送所有请求
function fetchAny(urls) {
// 中断一个或多个请求
const controller = new AbortController()
const signal = controller.signal
// 遍历将所有的请求地址转换为promise
const PromiseAll = urls.map((url) => {
return new Promise((resolve, reject) => {
fetch(url, { signal })
.then(progress)
.then((res) => {
const r = res.clone()
if (r.status !== 200) reject(null)
controller.abort() // 中断
resolve(r)
})
.catch(() => reject(null))
})
})
// 判断浏览器是否支持 Promise.any
if (!Promise.any) createPromiseAny()
// 谁先返回"成功状态"则返回谁的内容,如果都返回"失败状态"则返回null
return Promise.any(PromiseAll)
.then((res) => res)
.catch(() => null)
}