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

使用for循环上传多文件到Google Cloud Storage时如何等待每个上传完成

问题原因

你遇到的问题是Node.js异步回调机制导致的:blobStream的finish、error事件回调都是异步执行的,同步的for循环不会等待这些回调触发,会直接遍历完所有文件后立刻执行最后的res.send逻辑,此时urlList还没有被异步回调填充数据,所以返回为空。

解决方案

将单个文件的上传逻辑封装为返回Promise的函数,在for循环中通过await等待当前文件的上传Promise执行完成(包括上传完成、设置公开权限成功)后,再进入下一轮循环。

完整修改后代码
const processFile = require('../middleware');
const { format } = require('util');
let uuidv4 = require('uuid/v4');

const Cloud = require('@google-cloud/storage');

const { Storage } = Cloud;
const storage = new Storage({
  keyFilename: './xxx.json',
  projectId: 'xxx'
});

const bucket = storage.bucket('xxx');

// 封装单个文件上传逻辑,返回Promise
const uploadSingleFile = (file) => {
  return new Promise(async (resolve, reject) => {
    const { originalname, buffer } = file;
    let filename = originalname
      .toLowerCase()
      .split(' ')
      .join('-');
    filename = uuidv4() + '-' + filename;

    const blob = bucket.file(filename);
    const blobStream = blob.createWriteStream({
      resumable: false
    });

    blobStream.on('error', err => {
      reject(err);
    });

    blobStream.on('finish', async () => {
      const publicUrl = format(`https://storage.googleapis.com/${bucket.name}/${blob.name}`);
      try {
        await blob.makePublic();
        resolve(publicUrl);
      } catch (err) {
        console.log('failed to make it public');
        reject(err);
      }
    });

    blobStream.end(buffer);
  })
}

exports.upload = async (req, res) => {
  const urlList = [];
  try {
    await processFile(req, res); //multer

    if (!req.files || req.files.length === 0) {
      return res.status(400).send({ message: 'Please upload a file!' });
    }

    // 串行等待每个文件上传完成
    for (let i = 0; i < req.files.length; i++) {
      const fileUrl = await uploadSingleFile(req.files[i]);
      urlList.push(fileUrl);
    }

    return res.status(200).send({
      message: 'Uploaded the files successfully',
      url: urlList
    });
  } catch (err) {
    return res.status(500).send({ message: err.message });
  }
};
额外说明

如果不需要严格按顺序上传,想要提升上传速度,可以改用Promise.all并行处理所有文件上传:

// 把上面的串行for循环替换为下面的代码即可
const uploadPromises = req.files.map(file => uploadSingleFile(file));
const urlList = await Promise.all(uploadPromises);

内容的提问来源于stack exchange,提问作者ssaqan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 11:15:03