mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-06-07 08:40:46 +08:00
添加全局请求和图片优化器
This commit is contained in:
128
src/utils/imageOptimizer.ts
Normal file
128
src/utils/imageOptimizer.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
let isNavigating = false
|
||||
const MAX_CONCURRENT_IMAGES = 10 // 并发数
|
||||
let currentLoadingCount = 0
|
||||
const imageQueue: { img: HTMLImageElement; src: string }[] = []
|
||||
|
||||
// 监听路由状态
|
||||
export function setNavigatingState(navigating: boolean) {
|
||||
isNavigating = navigating
|
||||
|
||||
if (navigating) {
|
||||
// 路由切换时只是标记状态,不强制中断图片加载
|
||||
console.log('Navigation started - pausing new image loads')
|
||||
} else {
|
||||
// 路由切换完成后,处理队列中的图片
|
||||
setTimeout(() => {
|
||||
console.log('Navigation ended - resuming image loads')
|
||||
processImageQueue()
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理图片队列
|
||||
function processImageQueue() {
|
||||
while (imageQueue.length > 0 && currentLoadingCount < MAX_CONCURRENT_IMAGES && !isNavigating) {
|
||||
const { img, src } = imageQueue.shift()!
|
||||
startImageLoad(img, src)
|
||||
}
|
||||
}
|
||||
|
||||
// 开始加载图片
|
||||
function startImageLoad(img: HTMLImageElement, src: string) {
|
||||
currentLoadingCount++
|
||||
|
||||
const originalOnLoad = img.onload
|
||||
const originalOnError = img.onerror
|
||||
|
||||
img.onload = function (event) {
|
||||
currentLoadingCount--
|
||||
processImageQueue() // 加载完成后处理队列
|
||||
if (originalOnLoad) originalOnLoad.call(this, event)
|
||||
}
|
||||
|
||||
img.onerror = function (event) {
|
||||
currentLoadingCount--
|
||||
processImageQueue() // 出错时也要处理队列
|
||||
if (originalOnError) originalOnError.call(this, event)
|
||||
}
|
||||
|
||||
img.src = src
|
||||
}
|
||||
|
||||
// 智能图片加载函数
|
||||
function smartImageLoad(img: HTMLImageElement, src: string) {
|
||||
if (isNavigating) {
|
||||
// 路由切换时,加入队列等待
|
||||
imageQueue.push({ img, src })
|
||||
return
|
||||
}
|
||||
|
||||
if (currentLoadingCount < MAX_CONCURRENT_IMAGES) {
|
||||
// 直接加载
|
||||
startImageLoad(img, src)
|
||||
} else {
|
||||
// 加入队列
|
||||
imageQueue.push({ img, src })
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化图片优化器
|
||||
export function initializeImageOptimizer() {
|
||||
// 只对新创建的img元素进行温和的优化
|
||||
const originalCreateElement = document.createElement
|
||||
document.createElement = function (tagName: string, options?: ElementCreationOptions) {
|
||||
const element = originalCreateElement.call(this, tagName, options)
|
||||
|
||||
if (tagName.toLowerCase() === 'img') {
|
||||
const img = element as HTMLImageElement
|
||||
|
||||
// 只拦截src的设置,使用更温和的方式
|
||||
const originalSetAttribute = img.setAttribute
|
||||
img.setAttribute = function (name: string, value: string) {
|
||||
if (name === 'src' && value) {
|
||||
// 使用智能加载
|
||||
smartImageLoad(this, value)
|
||||
return
|
||||
}
|
||||
return originalSetAttribute.call(this, name, value)
|
||||
}
|
||||
}
|
||||
|
||||
return element
|
||||
}
|
||||
|
||||
// 为现有图片添加懒加载属性
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const images = document.querySelectorAll('img:not([loading])')
|
||||
images.forEach(img => {
|
||||
img.setAttribute('loading', 'lazy')
|
||||
})
|
||||
})
|
||||
|
||||
// 监听新添加的图片
|
||||
const observer = new MutationObserver(mutations => {
|
||||
mutations.forEach(mutation => {
|
||||
mutation.addedNodes.forEach(node => {
|
||||
if (node.nodeType === Node.ELEMENT_NODE) {
|
||||
const element = node as Element
|
||||
|
||||
// 为新添加的img标签设置懒加载
|
||||
if (element.tagName === 'IMG' && !element.getAttribute('loading')) {
|
||||
element.setAttribute('loading', 'lazy')
|
||||
}
|
||||
|
||||
// 为子元素中的img设置懒加载
|
||||
const imgs = element.querySelectorAll('img:not([loading])')
|
||||
imgs.forEach(img => {
|
||||
img.setAttribute('loading', 'lazy')
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
observer.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
})
|
||||
}
|
||||
98
src/utils/requestOptimizer.ts
Normal file
98
src/utils/requestOptimizer.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
// 全局请求优化器
|
||||
// 自动管理所有API请求的中断,无需手动注册
|
||||
|
||||
let isNavigating = false
|
||||
const activeRequests = new Set<AbortController>()
|
||||
|
||||
// 监听路由状态
|
||||
export function setNavigatingState(navigating: boolean) {
|
||||
isNavigating = navigating
|
||||
|
||||
if (navigating) {
|
||||
// 路由切换时,中断所有未完成的请求
|
||||
console.log('Navigation started - aborting active requests')
|
||||
abortAllActiveRequests()
|
||||
}
|
||||
}
|
||||
|
||||
// 中断所有活跃的请求
|
||||
function abortAllActiveRequests() {
|
||||
for (const controller of activeRequests) {
|
||||
if (!controller.signal.aborted) {
|
||||
controller.abort()
|
||||
}
|
||||
}
|
||||
activeRequests.clear()
|
||||
}
|
||||
|
||||
// 清理已完成的请求控制器
|
||||
function cleanupController(controller: AbortController) {
|
||||
activeRequests.delete(controller)
|
||||
}
|
||||
|
||||
// 初始化请求优化器
|
||||
export function initializeRequestOptimizer(axiosInstance: any) {
|
||||
// 拦截请求,自动添加 AbortController
|
||||
axiosInstance.interceptors.request.use(
|
||||
(config: any) => {
|
||||
// 如果请求已经有 signal,跳过(避免覆盖手动设置的)
|
||||
if (config.signal) {
|
||||
return config
|
||||
}
|
||||
|
||||
// 创建新的 AbortController
|
||||
const controller = new AbortController()
|
||||
config.signal = controller.signal
|
||||
|
||||
// 将控制器添加到活跃列表
|
||||
activeRequests.add(controller)
|
||||
|
||||
// 监听请求完成事件来清理控制器
|
||||
const cleanup = () => cleanupController(controller)
|
||||
|
||||
// 监听中断事件
|
||||
controller.signal.addEventListener('abort', cleanup, { once: true })
|
||||
|
||||
return config
|
||||
},
|
||||
(error: any) => {
|
||||
return Promise.reject(error)
|
||||
},
|
||||
)
|
||||
|
||||
// 拦截响应,清理对应的控制器
|
||||
axiosInstance.interceptors.response.use(
|
||||
(response: any) => {
|
||||
// 从配置中获取 signal 对应的控制器并清理
|
||||
if (response.config?.signal) {
|
||||
const controller = Array.from(activeRequests).find(ctrl => ctrl.signal === response.config.signal)
|
||||
if (controller) {
|
||||
cleanupController(controller)
|
||||
}
|
||||
}
|
||||
return response
|
||||
},
|
||||
(error: any) => {
|
||||
// 错误时也要清理控制器
|
||||
if (error.config?.signal) {
|
||||
const controller = Array.from(activeRequests).find(ctrl => ctrl.signal === error.config.signal)
|
||||
if (controller) {
|
||||
cleanupController(controller)
|
||||
}
|
||||
}
|
||||
return Promise.reject(error)
|
||||
},
|
||||
)
|
||||
|
||||
console.log('Request optimizer initialized - all requests will be auto-managed')
|
||||
}
|
||||
|
||||
// 获取当前活跃请求数量(调试用)
|
||||
export function getActiveRequestsCount() {
|
||||
return activeRequests.size
|
||||
}
|
||||
|
||||
// 手动中断所有请求(备用方法)
|
||||
export function abortAllRequests() {
|
||||
abortAllActiveRequests()
|
||||
}
|
||||
Reference in New Issue
Block a user