DrkStr
DrkStr

Reputation: 1932

Trouble with Promises and Callbacks in JS

I am trying to get a list of objects out of an S3 bucket and when I have a list of objects I would like to generate pre-signed URLs for these objects. The only way I could figure out how to do this was to use nested callback functions like so:

exports.handler = async (event, context, callback) => {
console.log('processing event: %j', event);

const bucket = process.env['s3_bucket'];
if (!bucket) {
    callback(new Error("s3 bucket not set"));
}

const deviceId = event['deviceId'];

const params = getListObjectsParams(deviceId, bucket);
let count = 0;

await s3.listObjectsV2(params, function (err, data) {
    if (err) callback("Error getting image list: " + err);
    else {
        data.Contents.forEach(function (image) {
            count = count + 1;
            const objectParams = getObjectParams(bucket, image.Key);
            s3.getSignedUrl('getObject', objectParams, function (err, url) {
                if (err) {
                    console.log("Error");
                    console.log(err);
                    //TODO: log error getting pre signed url
                } else {
                    images.push(url);
                }
            });

        });
    }
});

callback(null, images);

};

I am having some trouble returning the images array as the function is completing before the calls to listObjectsV2 and each of the getSignedUrl complete. Here are my questions.

  1. How do I get the execution to wait for promises to complete before completing executing the function?
  2. If there a better way to layout this block of code, nesting callbacks look messy :(

Upvotes: 0

Views: 191

Answers (2)

jarmod
jarmod

Reputation: 78703

The AWS JavaScript SDK natively supports promises. Instead of this:

s3.listObjectsV2(params, function (err, data) {
    // do something with data here in the callback
});

write this:

const data = await s3.listObjectsV2(params).promise();
// do something with data here

Note that await may only be used in an async function. If you aren't in an async function then you can fabricate one as follows (an immediately invoked async arrow function):

(async () => {
    const data = await s3.listObjectsV2(params).promise();
    // do something with data here
})();

Upvotes: 1

Quentin
Quentin

Reputation: 943591

How do I get the execution to wait for promises to complete before completing executing the function?

Inside an async function, put await in front of a promise.

You've done the first two of those, but s3.listObjectsV2 doesn't return a promise.

If you want to use await with it then you must convert the existing callback API to a promise

Upvotes: 1

Related Questions