mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-05 23:56:42 +08:00
优化服务工作者
This commit is contained in:
+55
-39
@@ -155,14 +155,14 @@ async function clearBadge() {
|
|||||||
async function deleteOldCaches() {
|
async function deleteOldCaches() {
|
||||||
const cacheWhitelist = Object.values(CACHE_NAMES)
|
const cacheWhitelist = Object.values(CACHE_NAMES)
|
||||||
const cacheNames = await caches.keys()
|
const cacheNames = await caches.keys()
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
cacheNames.map(async (cacheName) => {
|
cacheNames.map(async cacheName => {
|
||||||
if (!cacheWhitelist.includes(cacheName)) {
|
if (!cacheWhitelist.includes(cacheName)) {
|
||||||
console.log('Deleting old cache:', cacheName)
|
console.log('Deleting old cache:', cacheName)
|
||||||
return caches.delete(cacheName)
|
return caches.delete(cacheName)
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,12 +171,12 @@ async function getCacheSize(cacheName: string): Promise<number> {
|
|||||||
if (!('estimate' in navigator.storage)) {
|
if (!('estimate' in navigator.storage)) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const cache = await caches.open(cacheName)
|
const cache = await caches.open(cacheName)
|
||||||
const keys = await cache.keys()
|
const keys = await cache.keys()
|
||||||
let totalSize = 0
|
let totalSize = 0
|
||||||
|
|
||||||
for (const request of keys) {
|
for (const request of keys) {
|
||||||
const response = await cache.match(request)
|
const response = await cache.match(request)
|
||||||
if (response) {
|
if (response) {
|
||||||
@@ -184,7 +184,7 @@ async function getCacheSize(cacheName: string): Promise<number> {
|
|||||||
totalSize += blob.size
|
totalSize += blob.size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalSize
|
return totalSize
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to get cache size:', error)
|
console.error('Failed to get cache size:', error)
|
||||||
@@ -196,13 +196,13 @@ async function getCacheSize(cacheName: string): Promise<number> {
|
|||||||
async function monitorCacheSize() {
|
async function monitorCacheSize() {
|
||||||
const cacheSizes: Record<string, number> = {}
|
const cacheSizes: Record<string, number> = {}
|
||||||
let totalSize = 0
|
let totalSize = 0
|
||||||
|
|
||||||
for (const [key, cacheName] of Object.entries(CACHE_NAMES)) {
|
for (const [key, cacheName] of Object.entries(CACHE_NAMES)) {
|
||||||
const size = await getCacheSize(cacheName)
|
const size = await getCacheSize(cacheName)
|
||||||
cacheSizes[key] = size
|
cacheSizes[key] = size
|
||||||
totalSize += size
|
totalSize += size
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发送缓存统计信息给客户端
|
// 发送缓存统计信息给客户端
|
||||||
const clients = await self.clients.matchAll()
|
const clients = await self.clients.matchAll()
|
||||||
clients.forEach(client => {
|
clients.forEach(client => {
|
||||||
@@ -212,10 +212,10 @@ async function monitorCacheSize() {
|
|||||||
cacheSizes,
|
cacheSizes,
|
||||||
totalSize,
|
totalSize,
|
||||||
totalSizeMB: (totalSize / 1024 / 1024).toFixed(2),
|
totalSizeMB: (totalSize / 1024 / 1024).toFixed(2),
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return { cacheSizes, totalSize }
|
return { cacheSizes, totalSize }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,16 +224,16 @@ async function cleanupExpiredCaches() {
|
|||||||
for (const [key, cacheName] of Object.entries(CACHE_NAMES)) {
|
for (const [key, cacheName] of Object.entries(CACHE_NAMES)) {
|
||||||
const limit = CACHE_SIZE_LIMITS[key as keyof typeof CACHE_SIZE_LIMITS]
|
const limit = CACHE_SIZE_LIMITS[key as keyof typeof CACHE_SIZE_LIMITS]
|
||||||
if (!limit) continue
|
if (!limit) continue
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const cache = await caches.open(cacheName)
|
const cache = await caches.open(cacheName)
|
||||||
const keys = await cache.keys()
|
const keys = await cache.keys()
|
||||||
|
|
||||||
// 如果缓存条目超过限制,删除最老的条目
|
// 如果缓存条目超过限制,删除最老的条目
|
||||||
if (keys.length > limit.maxEntries) {
|
if (keys.length > limit.maxEntries) {
|
||||||
const deleteCount = keys.length - limit.maxEntries
|
const deleteCount = keys.length - limit.maxEntries
|
||||||
console.log(`Cleaning up ${deleteCount} entries from ${cacheName}`)
|
console.log(`Cleaning up ${deleteCount} entries from ${cacheName}`)
|
||||||
|
|
||||||
// 删除最老的条目(假设数组开头是最老的)
|
// 删除最老的条目(假设数组开头是最老的)
|
||||||
for (let i = 0; i < deleteCount; i++) {
|
for (let i = 0; i < deleteCount; i++) {
|
||||||
await cache.delete(keys[i])
|
await cache.delete(keys[i])
|
||||||
@@ -262,10 +262,10 @@ self.addEventListener('activate', event => {
|
|||||||
|
|
||||||
// 清理旧版本的缓存
|
// 清理旧版本的缓存
|
||||||
await deleteOldCaches()
|
await deleteOldCaches()
|
||||||
|
|
||||||
// 清理过期的缓存条目
|
// 清理过期的缓存条目
|
||||||
await cleanupExpiredCaches()
|
await cleanupExpiredCaches()
|
||||||
|
|
||||||
// 监控缓存大小
|
// 监控缓存大小
|
||||||
await monitorCacheSize()
|
await monitorCacheSize()
|
||||||
})(),
|
})(),
|
||||||
@@ -313,7 +313,7 @@ self.addEventListener('fetch', event => {
|
|||||||
}
|
}
|
||||||
})(),
|
})(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// POST/PUT/DELETE请求:离线时加入同步队列
|
// POST/PUT/DELETE请求:离线时加入同步队列
|
||||||
else if (['POST', 'PUT', 'DELETE', 'PATCH'].includes(event.request.method)) {
|
else if (['POST', 'PUT', 'DELETE', 'PATCH'].includes(event.request.method)) {
|
||||||
event.respondWith(
|
event.respondWith(
|
||||||
@@ -325,7 +325,7 @@ self.addEventListener('fetch', event => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 网络错误时,加入同步队列
|
// 网络错误时,加入同步队列
|
||||||
await addToSyncQueue(event.request)
|
await addToSyncQueue(event.request)
|
||||||
|
|
||||||
// 通知客户端请求已加入队列
|
// 通知客户端请求已加入队列
|
||||||
if (self.clients) {
|
if (self.clients) {
|
||||||
self.clients.matchAll().then(clients => {
|
self.clients.matchAll().then(clients => {
|
||||||
@@ -338,18 +338,18 @@ self.addEventListener('fetch', event => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回一个假的成功响应
|
// 返回一个假的成功响应
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
success: true,
|
success: true,
|
||||||
queued: true,
|
queued: true,
|
||||||
message: '请求已加入离线队列,将在网络恢复后自动同步'
|
message: '请求已加入离线队列,将在网络恢复后自动同步',
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
status: 202,
|
status: 202,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})(),
|
})(),
|
||||||
@@ -373,7 +373,7 @@ async function addToSyncQueue(request: Request) {
|
|||||||
const id = `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
|
const id = `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
|
||||||
const url = request.url
|
const url = request.url
|
||||||
const method = request.method
|
const method = request.method
|
||||||
|
|
||||||
let data: any = null
|
let data: any = null
|
||||||
if (method !== 'GET' && method !== 'HEAD') {
|
if (method !== 'GET' && method !== 'HEAD') {
|
||||||
try {
|
try {
|
||||||
@@ -382,7 +382,7 @@ async function addToSyncQueue(request: Request) {
|
|||||||
console.error('Failed to read request body:', e)
|
console.error('Failed to read request body:', e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const syncItem = {
|
const syncItem = {
|
||||||
id,
|
id,
|
||||||
url,
|
url,
|
||||||
@@ -390,11 +390,11 @@ async function addToSyncQueue(request: Request) {
|
|||||||
data,
|
data,
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存到IndexedDB (使用专用的 "sync" store)
|
// 保存到IndexedDB (使用专用的 "sync" store)
|
||||||
await set(id, syncItem, 'sync')
|
await set(id, syncItem, 'sync')
|
||||||
syncQueue.push(syncItem)
|
syncQueue.push(syncItem)
|
||||||
|
|
||||||
// 注册后台同步
|
// 注册后台同步
|
||||||
if ('sync' in self.registration) {
|
if ('sync' in self.registration) {
|
||||||
await self.registration.sync.register('sync-data')
|
await self.registration.sync.register('sync-data')
|
||||||
@@ -405,16 +405,19 @@ async function addToSyncQueue(request: Request) {
|
|||||||
async function processSyncQueue() {
|
async function processSyncQueue() {
|
||||||
const db = await openDB()
|
const db = await openDB()
|
||||||
|
|
||||||
// 使用专用的 "sync" store,并开启 readwrite 事务(便于后续删除)
|
// 先用只读事务获取所有同步项
|
||||||
const tx = db.transaction(['sync'], 'readwrite')
|
|
||||||
const store = tx.objectStore('sync')
|
|
||||||
|
|
||||||
const items: Array<any> = await new Promise((resolve, reject) => {
|
const items: Array<any> = await new Promise((resolve, reject) => {
|
||||||
|
const tx = db.transaction(['sync'], 'readonly')
|
||||||
|
const store = tx.objectStore('sync')
|
||||||
const req = store.getAll()
|
const req = store.getAll()
|
||||||
req.onsuccess = () => resolve(req.result)
|
req.onsuccess = () => resolve(req.result)
|
||||||
req.onerror = () => reject(req.error)
|
req.onerror = () => reject(req.error)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 收集需要删除的项目ID
|
||||||
|
const itemsToDelete: string[] = []
|
||||||
|
const itemsToDeleteExpired: string[] = []
|
||||||
|
|
||||||
for (const syncItem of items) {
|
for (const syncItem of items) {
|
||||||
const key = syncItem.id
|
const key = syncItem.id
|
||||||
try {
|
try {
|
||||||
@@ -434,8 +437,8 @@ async function processSyncQueue() {
|
|||||||
const response = await fetch(syncItem.url, init)
|
const response = await fetch(syncItem.url, init)
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
// 成功后删除同步项,并等待事务完成
|
// 成功后标记为需要删除
|
||||||
await del(key, 'sync')
|
itemsToDelete.push(key)
|
||||||
|
|
||||||
// 通知客户端同步成功
|
// 通知客户端同步成功
|
||||||
const clients = await self.clients.matchAll()
|
const clients = await self.clients.matchAll()
|
||||||
@@ -452,12 +455,29 @@ async function processSyncQueue() {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Sync failed for item:', key, error)
|
console.error('Sync failed for item:', key, error)
|
||||||
|
|
||||||
// 如果该同步项已存在超过 24 小时,则将其丢弃
|
// 如果该同步项已存在超过 24 小时,则标记为需要删除
|
||||||
if (Date.now() - syncItem.timestamp > 24 * 60 * 60 * 1000) {
|
if (Date.now() - syncItem.timestamp > 24 * 60 * 60 * 1000) {
|
||||||
await del(key, 'sync')
|
itemsToDeleteExpired.push(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 批量删除所有成功处理的项目和过期项目
|
||||||
|
const allItemsToDelete = [...itemsToDelete, ...itemsToDeleteExpired]
|
||||||
|
if (allItemsToDelete.length > 0) {
|
||||||
|
await new Promise<void>((resolve, reject) => {
|
||||||
|
const tx = db.transaction(['sync'], 'readwrite')
|
||||||
|
const store = tx.objectStore('sync')
|
||||||
|
|
||||||
|
// 批量删除所有标记的项目
|
||||||
|
allItemsToDelete.forEach(id => {
|
||||||
|
store.delete(id)
|
||||||
|
})
|
||||||
|
|
||||||
|
tx.oncomplete = () => resolve()
|
||||||
|
tx.onerror = () => reject(tx.error)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化 Workbox
|
// 初始化 Workbox
|
||||||
@@ -552,11 +572,7 @@ self.addEventListener('message', function (event) {
|
|||||||
})
|
})
|
||||||
} else if (event.data && event.data.type === 'CLEANUP_CACHES') {
|
} else if (event.data && event.data.type === 'CLEANUP_CACHES') {
|
||||||
// 手动触发缓存清理
|
// 手动触发缓存清理
|
||||||
Promise.all([
|
Promise.all([deleteOldCaches(), cleanupExpiredCaches(), monitorCacheSize()])
|
||||||
deleteOldCaches(),
|
|
||||||
cleanupExpiredCaches(),
|
|
||||||
monitorCacheSize()
|
|
||||||
])
|
|
||||||
.then(([, , cacheInfo]) => {
|
.then(([, , cacheInfo]) => {
|
||||||
event.ports[0]?.postMessage({ success: true, cacheInfo })
|
event.ports[0]?.postMessage({ success: true, cacheInfo })
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user