From 6b3eab4616b313bec15c4067237c36925b5c7eac Mon Sep 17 00:00:00 2001 From: Jad Date: Fri, 26 Dec 2025 17:35:03 +0800 Subject: [PATCH] perf: optimize batch processing efficiency --- src/app.js | 82 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 32 deletions(-) diff --git a/src/app.js b/src/app.js index e3883b4..5ae8044 100644 --- a/src/app.js +++ b/src/app.js @@ -47,7 +47,7 @@ async function init() { }) } catch (error) { hideLoading(); - console.error('初始化错误:', error); + console.error('initialize error:', error); } } @@ -112,13 +112,20 @@ function handleFiles(files) { if (validFiles.length === 0) return; + imageQueue.forEach(item => { + if (item.originalUrl) URL.revokeObjectURL(item.originalUrl); + if (item.processedUrl) URL.revokeObjectURL(item.processedUrl); + }); + imageQueue = validFiles.map((file, index) => ({ id: Date.now() + index, file, name: file.name, status: 'pending', originalImg: null, - processedBlob: null + processedBlob: null, + originalUrl: null, + processedUrl: null })); processedCount = 0; @@ -160,7 +167,8 @@ async function processSingle(item) { const blob = await new Promise(resolve => result.toBlob(resolve, 'image/png')); item.processedBlob = blob; - processedImage.src = URL.createObjectURL(blob); + item.processedUrl = URL.createObjectURL(blob); + processedImage.src = item.processedUrl; processedSection.style.display = 'block'; downloadBtn.style.display = 'flex'; downloadBtn.onclick = () => downloadImage(item); @@ -203,47 +211,57 @@ function createImageCard(item) { } async function processQueue() { - for (const item of imageQueue) { + await Promise.all(imageQueue.map(async item => { const img = await loadImage(item.file); item.originalImg = img; + item.originalUrl = img.src; document.getElementById(`result-${item.id}`).src = img.src; zoom.attach(`#result-${item.id}`); - } + })); - for (const item of imageQueue) { - if (item.status !== 'pending') continue; + const concurrency = 3; + for (let i = 0; i < imageQueue.length; i += concurrency) { + await Promise.all(imageQueue.slice(i, i + concurrency).map(async item => { + if (item.status !== 'pending') return; - item.status = 'processing'; - updateStatus(item.id, i18n.t('status.processing')); + item.status = 'processing'; + updateStatus(item.id, i18n.t('status.processing')); - try { - const result = await engine.removeWatermarkFromImage(item.originalImg); - const blob = await new Promise(resolve => result.toBlob(resolve, 'image/png')); - item.processedBlob = blob; + try { + const result = await engine.removeWatermarkFromImage(item.originalImg); + const blob = await new Promise(resolve => result.toBlob(resolve, 'image/png')); + item.processedBlob = blob; - document.getElementById(`result-${item.id}`).src = URL.createObjectURL(blob); + item.processedUrl = URL.createObjectURL(blob); + document.getElementById(`result-${item.id}`).src = item.processedUrl; - item.status = 'completed'; - const watermarkInfo = engine.getWatermarkInfo(item.originalImg.width, item.originalImg.height); - const { is_google, is_original } = await checkOriginal(item.originalImg); - const originalStatus = getOriginalStatus({ is_google, is_original }); + item.status = 'completed'; + const watermarkInfo = engine.getWatermarkInfo(item.originalImg.width, item.originalImg.height); - updateStatus(item.id, `

${i18n.t('info.size')}: ${item.originalImg.width}×${item.originalImg.height}

+ updateStatus(item.id, `

${i18n.t('info.size')}: ${item.originalImg.width}×${item.originalImg.height}

${i18n.t('info.watermark')}: ${watermarkInfo.size}×${watermarkInfo.size}

-

${i18n.t('info.position')}: (${watermarkInfo.position.x},${watermarkInfo.position.y})

-

${originalStatus}

`, true); +

${i18n.t('info.position')}: (${watermarkInfo.position.x},${watermarkInfo.position.y})

`, true); - const downloadBtn = document.getElementById(`download-${item.id}`); - downloadBtn.classList.remove('hidden'); - downloadBtn.onclick = () => downloadImage(item); + const downloadBtn = document.getElementById(`download-${item.id}`); + downloadBtn.classList.remove('hidden'); + downloadBtn.onclick = () => downloadImage(item); - processedCount++; - updateProgress(); - } catch (error) { - item.status = 'error'; - updateStatus(item.id, i18n.t('status.failed')); - console.error(error); - } + processedCount++; + updateProgress(); + + checkOriginal(item.originalImg).then(({ is_google, is_original }) => { + if (!is_google || !is_original) { + const status = getOriginalStatus({ is_google, is_original }); + const statusEl = document.getElementById(`status-${item.id}`); + if (statusEl) statusEl.innerHTML += `

${status}

`; + } + }).catch(() => {}); + } catch (error) { + item.status = 'error'; + updateStatus(item.id, i18n.t('status.failed')); + console.error(error); + } + })); } if (processedCount > 0) { @@ -268,7 +286,7 @@ function updateDynamicTexts() { function downloadImage(item) { const a = document.createElement('a'); - a.href = URL.createObjectURL(item.processedBlob); + a.href = item.processedUrl; a.download = `unwatermarked_${item.name.replace(/\.[^.]+$/, '')}.png`; a.click(); }