0

I'm new to Nodejs and having trouble understand this issue: I tried to run a describe function against an array, and the AWS function seems to run after the main function has finished.

Here's the main function: (loop thru a list of ACM ARNs and check the status)

var checkCertStatus = function(resolveObj){
    var promise = new Promise(function(resolve, reject){

        console.log('1');
        var retObj='';
        resolveObj.Items.forEach(function(element) {
            var certDescribeParams = {
                CertificateArn: element.sslCertId
            };
            console.log('2');
            acm.describeCertificate(certDescribeParams, function(err, data) {
                if(err) reject(new Error(err));
                else     {
                    console.log(data.Certificate.DomainName + ': ' + data.Certificate.Status);
                    retObj+=data;
                }
            });
        });
        console.log('3');
        resolve(retObj);
        return promise;
    })
}

Based on the debug log, assuming there are 2 items need to be processed, what I got:

1
2
2
3
example.com: ISSUED
example2.com: ISSUED

Basically, I need to pass this result to the next function in the chain (with promise and stuff).

1 Answer 1

1

Welcome to Node.js! Speaking generally, it might be helpful to study up on the asynchronous programming style. In particular, you seem to be mixing Promises and callbacks, which may make this example more confusing than it needs to be. I suggest using the AWS SDK's built-in feature to convert responses to Promises.

The first thing I notice is that you are manually constructing a Promise with a resolve/reject function. This is often a red flag unless you are creating a library. Most other libraries support Promises which you can simply use and chain. (This includes AWS SDK, as mentioned above.)

The second thing I notice is that your checkCertStatus function does not return anything. It creates a Promise but does not return it at the end. Your return promise; line is actually inside the callback function used to create the Promise.

Personally, when working with Promises, I prefer to use the Bluebird library. It provides more fully-featured Promises than native, including methods such as map. Conveniently, the AWS SDK can be configured to work with an alternative Promise constructor via AWS.config.setPromisesDependency() as documented here.

To simplify your logic, you might try something along these lines (untested code):

const Promise = require('bluebird');
AWS.config.setPromisesDependency(Promise);

const checkCertStatus = (resolveObj) => {
    const items = resolveObj.Items;
    console.log(`Mapping ${items.length} item(s)`);
    return Promise.resolve(items)
        .map((item) => {
            const certDescribeParams = {
                CertificateArn: item.sslCertId,
            };
            console.log(`Calling describeCertificate for ${item.sslCertId}`);
            return acm.describeCertificate(certDescribeParams)
                .promise()
                .then((data) => {
                    console.log(`${data.Certificate.DomainName}: ${data.Certificate.Status}`);
                    return data;
                });
        });
};

We're defining checkCertStatus as a function which takes in resolveObj and returns a Promise chain starting from resolveObj.Items. (I apologize if you are not yet familiar with Arrow Functions.) The first and only step in this chain is to map the items array to a new array of Promises returned from the acm.describeCertificate method. If any one of these individual Promises fails, the top-level Promise chain will reject as well. Otherwise, the top-level Promise chain will resolve to an array of the results. (Note that I included an inessential .then step just to log the individual results, but you could remove that clause entirely.)

Hope this helps, and I apologize if I left any mistakes in the code.

Sign up to request clarification or add additional context in comments.

1 Comment

Looking over my answer, I think, rather than the resolve/.map combo, you could just use Promise.map(items, <func>), where <func> is the argument to .map above. It's basically a shorthand.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.