首页 > 解决方案 > 无法弄清楚如何将数据异步推送到数组

问题描述

这是我编写的一个函数,用于检索我存储在 S3 存储桶中的文件的元数据。

它将存储桶中所有文件的键存储在一个数组中,然后遍历该数组以获取每个单独文件的元数据。问题是我存储值的元数据数组总是空的。

我在值被推入数组的位置之后立即输入了一个打印语句,并且该数组似乎被很好地填充,但是当我在该循环之外打印它时它打印为空。

我发现这是因为元数据被异步获取,并且数组显示为空,因为我在它实际填充值之前打印它。但我似乎无法弄清楚如何将值异步存储在数组中。一些帮助将不胜感激。

exports.allMetadata = (req, res) => {

    const params = {
        Bucket: env.Bucket
    }
    var metadata = [];
    s3.listObjectsV2(params, (err, data) => {
        if (err) {
            console.log(err, err.stack);
            res.send("error -> "+ err);
        } else {
            var contents = data.Contents;
            contents.forEach(content => {
                const params1 = {
                    Bucket: env.Bucket,
                    Key: content.Key
                };
                s3.headObject(params1, (err, data) => {
                    if (err) {
                        console.log(err, err.stack);
                        res.send("error -> "+ err);
                    } else {
                        metadata.push(data.Metadata);
                        console.log(metadata); //Prints fine
                    }
                });
            });
            console.log(metadata); //Shows empty here
            //res.send(metadata);
        }
    });
}

标签: javascriptnode.jsarraysasynchronousasync-await

解决方案


正如您所说,这s3.headObject是一个异步操作,因此您需要在将响应发送给客户端之前等待它们:

exports.allMetadata = (req, res) => {
  const params = {
    Bucket: env.Bucket
  }

  s3.listObjectsV2(params, (err, data) => {
    if (err) {
      console.log(err, err.stack)
      res.send('error -> ' + err)
      return
    }

    var contents = data.Contents
    const promiseArray = contents.map(content => {
      const params1 = {
        Bucket: env.Bucket,
        Key: content.Key
      }
      return readS3Meta(params1)
    })

    // WARN: the array should be not HUGE
    Promise.all(promiseArray)
      .then((allMetadata) => {
        console.log(allMetadata)
        res.send(allMetadata)
      })
      .catch(err => {
        res.send('error -> ' + err)
      })
  })
}

function readS3Meta (params1) {
  return new Promise((resolve, reject) => {
    s3.headObject(params1, (err, data) => {
      if (err) {
        console.log(err, err.stack)
        reject(err)
        return
      }
      resolve(data.Metadata)
    })
  })
}


推荐阅读