NodeJS中无法让程序在执行下一个函数前暂停的问题求助
问题排查与解决方案
问题根源
forEach不支持异步等待:resizeImages函数中使用await images.forEach(async (image) => { ... }),但forEach会立即遍历所有元素,不会等待每个异步回调执行完毕,导致resizeImages在所有图片缩放完成前就返回,进而提前触发压缩操作。compressImages未正确封装Promise:compressImages标记为async,但内部调用的compress-images是回调式API,未转为Promise,导致await无法等待压缩完成(次要问题,核心问题是缩放流程未同步)。
修复方案
1. 修复缩放函数的异步等待逻辑
将forEach替换为for...of循环,确保每个图片的异步缩放操作完成后,再执行下一个任务。
2. 封装压缩函数为Promise
把回调式的compress-images转为Promise,让await可以正确等待压缩流程结束。
修改后的完整代码
const path = require('path'); const fs = require('fs'); const jimp = require('jimp'); const compress_images = require('compress-images'); // 获取文件夹内所有图片路径 function getImagesPath(directory) { const directoryPath = path.join(__dirname, directory); const images = fs.readdirSync(directoryPath); return images.map(image => path.join(__dirname, directory, image)); } // 检查图片日期是否与当前日期相同 function isSameDate(imgPath, currentDate) { const imgDate = fs.statSync(imgPath).birthtime.toDateString(); return imgDate === currentDate; } // 检查图片是否超过大小限制(300kb) function checkSize(imgPath) { const limit = 300000; const imgSize = fs.statSync(imgPath).size; return imgSize >= limit; } // 缩放图片(修复异步等待逻辑) async function resizeImages(images, saveFolder) { const shrinkPercentage = 60; const directoryPath = path.join(__dirname, saveFolder); const currentDate = new Date().toDateString(); // 使用for...of替代forEach,确保等待每个异步操作完成 for (const image of images) { // 跳过不符合条件的图片 // if (!isSameDate(image, currentDate)) continue; if (!checkSize(image)) continue; const img = await jimp.read(image); // 简化尺寸计算逻辑 let width = img.bitmap.width * (1 - shrinkPercentage / 100); let height = img.bitmap.height * (1 - shrinkPercentage / 100); if (width < 732) { width = 732; await img.resize(width, jimp.AUTO); } else { await img.resize(width, height); } const newImageName = `${path.parse(image).name}-${width}X${height}${path.parse(image).ext}`; await img.write(path.join(directoryPath, newImageName)); } } // 压缩图片(封装为Promise) function compressImages(inputFolder, outputFolder) { return new Promise((resolve, reject) => { compress_images( inputFolder, outputFolder, { compress_force: true, statistic: true, autoupdate: true }, false, { jpg: { engine: "mozjpeg", command: ["-quality", "60"] } }, { png: { engine: "pngquant", command: ["--quality=20-50", "-o"] } }, { svg: { engine: false} }, { gif: { engine: false} }, function (error, completed, statistic) { console.log("-------------"); console.log(error); console.log(completed); console.log(statistic); console.log("-------------"); error ? reject(error) : resolve({ completed, statistic }); } ); }); } // 主函数(增加错误捕获) async function main() { try { const images = getImagesPath('original'); await resizeImages(images, 'resized'); await compressImages('resized/**/*.{jpg,JPG,jpeg,JPEG,png}', 'compressed/'); console.log("所有图片处理完成"); } catch (err) { console.error("处理过程出错:", err); } } main();
关键修改点说明
getImagesPath用map简化了路径拼接逻辑,比forEach更简洁高效。resizeImages改用for...of循环,确保每个异步步骤执行完成后再进入下一次迭代,彻底解决缩放未完成就触发压缩的问题。compressImages改为返回Promise,让await可以正确等待压缩流程结束,同时保留了原有的回调日志输出。main函数增加try/catch捕获全局错误,方便调试定位问题。
内容的提问来源于stack exchange,提问作者Rhodey
相关产品推荐
相关产品推荐

