arraysnode.jsamazon-s3aws-sdkdebug-mode

Array populated in debug more but not in in normal mode in Node.js


In the code below, when I run in debug mode with a break-point at this line: content.push(data.Body.toString()); I can see that data is inserted to the content array.

However when I run the code normally, content comes back empty.

How can I get it to populate the array for downstream use?

var params = { Bucket: "thebucket", Prefix: "theprefix/" }
var content = [];
function getS3Data()
{    
var s3 = new aws.S3();
s3.listObjects(params, function (err, data) 
{        
    if (err) throw err; // an error occurred
    else 
    {            
        var i;
        for (i = 0; i < data.Contents.length; i++)              
        {
            var currentValue =  data.Contents[i];
            if(currentValue.Key.endsWith(params.Prefix) == false) 
            {
                var goParams = { Bucket: params.Bucket, Key: currentValue.Key };                   
                s3.getObject(goParams, function(err, data) 
                {                        
                    if (err) throw err; //error                        
                    content.push(data.Body.toString());       
                });
            };
        };            
    }//else
});//listObjects
}//getS3Data

getS3Data();

console.log(content); //prints empty here when run in non-debug.

Solution

  • The line:
    console.log(content)
    is being executed before the line:
    content.push(data.Body.toString());

    the function you are passing as a 2nd argument to s3.listObjects will be executed asynchronously. If you want to log out content you need to do it within the callback function meaning:

    s3.listObjects(params, function (err, data) {        
        if (err) throw err;
        else {            
            // ...
            console.log(content)
        }
    });
    

    A better approach would be to implement getS3Data with Promise so you can run code after the object listing is done for sure.

    function getS3Data() {
        return new Promise((resolve, reject) => {
            if (err) {
                reject(err)
            } else {
                const promises = []
                for (const i = 0; i < data.Contents.length; i++) {
                    const currentValue = data.Contents[i];
                    if (currentValue.Key.endsWith(params.Prefix) == false) {
                        const goParams = { Bucket: params.Bucket, Key: currentValue.Key };
                        promises.push(new Promise((res, rej) => {
                            s3.getObject(goParams, function (err, data) {
                                if (err) {
                                    rej(err); //error
                                } else {
                                    res(data.Body.toString());
                                }                        
                            });
                        }));
                    }
                }
                Promise.all(promises).then(resolve);
            }
        });
    }
    
    getS3Data()
        .then(result => { // this will actually be `content` from your code example
            console.log(result);
        }).catch(error => {
            console.error(error);
        })