简体   繁体   中英

Can't figure out how to push data to array asynchronously

This is a function I've written to retrieve the metadata of files I've stored in an S3 bucket.

It stores the keys of all the files in the bucket in an array and then loops through that array to get the metadata of each individual file. The problem is that the metadata array that I store the values in always turns up empty.

I put in a print statement right after where the values are getting pushed into the array and the array seems to be getting populated fine, but it prints as empty when I print it outside of that loop.

I've figured out that this is because of the metadata being fetched asynchronously, and that the array appears empty because I'm printing it before it actually gets filled with values. But I can't for the life of me seem to figure out how to store the values in the array asynchronously. Some help would be greatly appreciated.

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);
        }
    });
}

As you said, the s3.headObject is an async operation, so you need to wait them before sending the response to the client:

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)
    })
  })
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM