You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 17:35:16