refactor(image): optimize image processing with AsyncQueue

- Replaced the promise-based image processing with an AsyncQueue to manage concurrent tasks more efficiently.
- Improved error handling and logging during image size and metadata retrieval.
- Updated the addMultiple method in AsyncQueue to return a wait function for better task management.

Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
Innei
2025-05-11 21:40:27 +08:00
parent 7229ccfb86
commit 7047b76f58
2 changed files with 35 additions and 34 deletions

View File

@@ -6,6 +6,7 @@ import { Injectable, Logger, OnModuleInit } from '@nestjs/common'
import { ConfigsService } from '~/modules/configs/configs.service' import { ConfigsService } from '~/modules/configs/configs.service'
import { pickImagesFromMarkdown } from '~/utils/pic.util' import { pickImagesFromMarkdown } from '~/utils/pic.util'
import { AsyncQueue } from '~/utils/queue.util'
import { requireDepsWithInstall } from '~/utils/tool.util' import { requireDepsWithInstall } from '~/utils/tool.util'
import { HttpService } from './helper.http.service' import { HttpService } from './helper.http.service'
@@ -41,8 +42,8 @@ export class ImageService implements OnModuleInit {
(originImages ?? []).map((image) => [image.src, { ...image }]), (originImages ?? []).map((image) => [image.src, { ...image }]),
) )
const task = [] as Promise<ImageModel>[] const queue = new AsyncQueue(2)
for (const src of newImages) { const imageProcessingTasks = newImages.map((src) => async () => {
const originImage = oldImagesMap.get(src) const originImage = oldImagesMap.get(src)
const keys = new Set(Object.keys(originImage || {})) const keys = new Set(Object.keys(originImage || {}))
@@ -55,27 +56,27 @@ export class ImageService implements OnModuleInit {
) )
) { ) {
result.push(originImage) result.push(originImage)
continue return
} }
const promise = new Promise<ImageModel>((resolve) => {
try {
this.logger.log(`Get --> ${src}`) this.logger.log(`Get --> ${src}`)
this.getOnlineImageSizeAndMeta(src) const { size, accent, blurHash } =
.then(({ size, accent, blurHash }) => { await this.getOnlineImageSizeAndMeta(src)
const filename = src.split('/').pop() const filename = src.split('/').pop()
this.logger.debug( this.logger.debug(
`[${filename}]: height: ${size.height}, width: ${size.width}, accent: ${accent}`, `[${filename}]: height: ${size.height}, width: ${size.width}, accent: ${accent}`,
) )
resolve({ ...size, accent, src, blurHash }) result.push({ ...size, accent, src, blurHash })
}) } catch (error) {
.catch((error) => {
this.logger.error(`GET --> ${src} ${error.message}`) this.logger.error(`GET --> ${src} ${error.message}`)
const oldRecord = oldImagesMap.get(src) const oldRecord = oldImagesMap.get(src)
if (oldRecord) { if (oldRecord) {
resolve(oldRecord) result.push(oldRecord)
} else } else {
resolve({ result.push({
width: undefined, width: undefined,
height: undefined, height: undefined,
type: undefined, type: undefined,
@@ -83,16 +84,15 @@ export class ImageService implements OnModuleInit {
src: undefined, src: undefined,
blurHash: undefined, blurHash: undefined,
}) })
}) }
}
}) })
task.push(promise) // Add all tasks to the queue and wait for completion
} const wait = queue.addMultiple(imageProcessingTasks)
const images = await Promise.all(task) await wait()
result.push(...images)
// 老图片不要过滤,记录到列头 // 老图片不要过滤,记录到列头
if (originImages) { if (originImages) {
for (const oldImageRecord of originImages) { for (const oldImageRecord of originImages) {
const src = oldImageRecord.src const src = oldImageRecord.src

View File

@@ -34,6 +34,7 @@ export class AsyncQueue {
addMultiple(requests: (() => Promise<any>)[]) { addMultiple(requests: (() => Promise<any>)[]) {
this.queue.push(...requests) this.queue.push(...requests)
this.runNext() const wait = this.runNext()
return async () => await wait
} }
} }