With the Node 8.10 runtime AWS added a new async
handler syntax
async handler(event, context) {
return result;
}
while continuing to support the old callback
handler syntax.
handler(event, context, callback) {
callback(null, result);
}
From the number of messages posted on the Serverless Forums a lot of developers seem to believe the async
keyword is syntactic sugar that doesn’t do anything. In fact the new async
syntax is functionally the equivalent of
handler(event, context) {
return new Promise((resolve, reject) => resolve(result));
}
It’s important to understand that functions declared async
are actually returning a Promise
because it appears that Lambda is now checking the return value from your handler function to determine what it does next. When the handler returns a Promise
then Lambda waits for the promise to resolve using it’s resolved value as the result for the Lambda.
If I was to speculate on the internal workings of Lambda I would think that it looks something like this.
const p = handler(event, context, callback);
if (p instanceof Promise) {
p.then(result => callback(null, result)).catch(err => callback(err));
}
This has led to some common mistakes that would have worked if async
hadn’t been used. Look at the following example
async handler(event, context, callback) {
doSomething()
.then(result => callback(null, result));
}
What’s going on here and why doesn’t this work?
Using async
causes the handler()
to return a Promise
(promise #1) that resolves at the end of the function. As we step through the function we call doSomething()
which returns a Promise
(promise #2). Execution then proceeds to the next line of code which is the end of the function so promise #1 will now resolve with the value undefined
.
What happened to promise #2 and the .then()
? The .then()
is only executed after promise #2 resolves. While technically it’s a race to see which resolves first in practice promise #1 will always resolve before promise #2 resulting in undefined
being sent as the response from the Lambda.
Without the async
keyword this would have worked because the handler function would have returned undefined
instead of a Promise
.
This also has an interesting side effect that you can now return a Promise
from a handler function that hasn’t been delcared async
which allows code like
handler(event, context) {
return doSomething()
.then(res1 => somethingElse(res1))
.then(res2 => { message: `Value is ${res2}` });
}
Importantly it means you shouldn’t mix async
and callback
when using the Node 8.10 runtime.
Want to learn more about serverless applications and devops with AWS?
Sign up for our newsletter.