Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can I await this code but not use .then?

Tags:

Node.JS 10.15, serverless, lambdas, invoked locally

SAMPLE A) This Works:

export async function main(event) {
    const marketName = marketIdToNameMap[event.marketId];
    const marketObject = marketDirectory[marketName];
    const marketClient = await marketObject.fetchClient();

    const marketTime = await marketObject.getTime(marketClient);
    console.log(marketTime);
}

SAMPLE B) and this works:

export function main(event) {
    const marketName = marketIdToNameMap[event.marketId];
    const marketObject = marketDirectory[marketName];

    marketObject.fetchClient().then((marketClient)=>{
        marketObject.getTime(marketClient).then((result) => {
            console.log('<---------------> marker 1 <--------------->');
            console.log(result);
        });
    });
}

SAMPLE C) but this does not:

export async function main(event) {
    const marketName = marketIdToNameMap[event.marketId];
    const marketObject = marketDirectory[marketName];
    const marketClient = await marketObject.fetchClient();

    console.log('<---------------> marker 1 <--------------->');

    marketObject.getTime(marketClient).then((result) => {
        console.log('<---------------> marker 22 <--------------->');
        console.log(result);
    });
}

the guts of getTime are for all examples:

function getTime(marketClient){
    return new Promise((resolve, reject) => {
        return marketClient.getTime((err, result) => {
            if (err) {
                reject(err);
            }
            resolve(result);
        });
    }).catch(err => {
        throw err;
    });
}

clearly, it seems to be an issue with mixing async/awaits with classic promise then-ables. I would expect SAMPLE C to work because getTime() is returning a promise. However, the code simply finishes silently, never hitting the second marker. I have to put the first marker there just to be sure any code is run at all. It feels like i should be able to mix async/await and thenables, but i must not be considering something here.

@adrian, nope enter image description here

like image 983
zentechinc Avatar asked May 07 '19 05:05

zentechinc


People also ask

How can I use then instead of await?

Async/await and then() are very similar. The difference is that in an async function, JavaScript will pause the function execution until the promise settles. With then() , the rest of the function will continue to execute but JavaScript won't execute the .

Does await wait for then?

The await keyword before a promise makes JavaScript wait until that promise settles, and then: If it's an error, an exception is generated — same as if throw error were called at that very place. Otherwise, it returns the result.

Does await stop the code?

If you want to await multiple promises (run this promise in parallel) create an array of promises and then pass it to the Promise. all function. Promise creation starts the execution of asynchronous functionality. await only blocks the code execution within the async function.

What can I use instead of await in JavaScript?

There are a few alternative async/await transpilers to Regenerator, which take async code and attempt to convert to more traditional . then and . catch notation. In my experience, these transpilers work pretty well for simple functions, which await then return , perhaps with a try/catch block at most.


1 Answers

You're neither awaiting nor returning the promise from marketObject.getTime().then(), and this will result in that promise chain executing independently, the main function returning and the process closing. Remember.. then returns a promise too.

the solution is

await marketObject.getTime(marketClient).then(...

or

return marketObject.getTime(marketClient).then(...

either way chains the promise to the main function such that whatever executes it consistently waits for all promises to resolve (or reject).

I suspect Sample B works because the main is not async and Lambda will wait for the event-loop to complete. i.e. it will execute the promise chain even though main returned early.

https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html

If you don't use callback in your code, AWS Lambda will call it implicitly and the return value is null. When the callback is called, AWS Lambda continues the Lambda function invocation until the event loop is empty.

... and I suspect if you return a Promise (as you do in Sample C) then Lambda will simply terminate the process immediately once it resolves, which is does because you don't await/return the .then() chain, and thus the floating promise chain you've created will not execute.

like image 93
Meirion Hughes Avatar answered Oct 14 '22 07:10

Meirion Hughes