Já se passaram seis meses desde que a AWS Lambda adicionou suporte ao Node.js 8.10. Estou super feliz por finalmente poder utilizar async/awaitpoder, simplificando minhas funções do Lambda.
Enquanto isso, ajudei alguns clientes com seus projetos serverless Node.js 8.10. Percebi alguns erros recorrentes ao utilizar async/await que vou compartilhar abaixo.
Ainda utilizando callbacks
Muitas pessoas ainda estão utilizando callbacks em suas funções async:
module.exports.handler = async (event, context, cb) => {
const response = {
statusCode: 200,
body: JSON.stringify({ message: 'hello world' })
}
cb(null, response)
}
a alternativa mais simples seria:
module.exports.handler = async (event, context) => {
const response = {
statusCode: 200,
body: JSON.stringify({ message: 'hello world' })
}
return response
}
Esquecer de usar util.promisify
Antes do Node.js 8.10, o pacote Bluebird preenchia uma lacuna enorme. Ele fornece utilitários para converter funções baseadas em callback para Promises. Mas o módulo nativo util do Node.js 8.10 preencheu essa lacuna com a função promisify.
Por exemplo, agora podemos transformar a função readFile do módulo fs da seguinte maneira:
const fs = require('fs')
const { promisify } = require('util')
const readFile = promisify(fs.readFile)
Não há mais necessidade de usar o Bluebird. Uma dependência a menos, o que ajuda a reduzir o tempo de inicialização frio (cold start) de nossas funções.
Código sequencial desnecessário
async/await permite escrever código assíncrono como se ele fosse síncrono, o que é incrível. Não precisamos lidar com callback hell!
Por outro lado, também podemos deixar passar uma vantagem de não executar tarefas simultaneamente, quando apropriado.
Veja o seguinte código como exemplo:
async function getFixturesAndTeam(teamId) {
const fixtures = await fixtureModel.fetchAll()
const team = await teamModel.fetch(teamId)
return {
team,
fixtures: fixtures.filter(x => x.teamId === teamId)
}
}
Esta função é fácil de ler, mas sua implementação dificilmente é a ideal. teamModel.fetch não depende do resultado fixtureModel.fetchAll, então eles devem ser executados simultaneamente.
Aqui está como você pode melhorar:
async function getFixturesAndTeam(teamId) {
const fixturesPromise = fixtureModel.fetchAll()
const teamPromise = teamModel.fetch(teamId)
const fixtures = await fixturesPromise
const team = await teamPromise
return {
team,
fixtures: fixtures.filter(x => x.teamId === teamId)
}
}
Nesta versão, ambos fixtureModel.fetchAll e teamModel.fetch são iniciados simultaneamente.
Você também precisa estar atento ao usar map com async/await. O exemplo seguinte chamará cada teamModel.fetch sequencialmente:
async function getTeams(teamIds) {
const teams = _.map(teamIds, id => await teamModel.fetch(id))
return teams
}
Ao invés disso, podemos escrever:
async function getTeams(teamIds) {
const promises = _.map(teamIds, id => teamModel.fetch(id))
const teams = await Promise.all(promises)
return teams
}
No exemplo acima, mapeamos teamIds para um array de promises. Podemos então usar Promise.all para transformar esse array em uma única promise que retorna um array de equipes.
Nesse caso, teamModel.fetch é chamado simultaneamente e pode melhorar significativamente o tempo de execução.
async/await dentro de forEach
Este é um truque que pode pegar até desenvolvedores experientes em Node.js.
O problema é que código como esse não se comporta da maneira que você espera:
[ 1, 2, 3 ].forEach(async (x) => {
await sleep(x)
console.log(x)
})
console.log('all done.')
Quando você executar isso, você obterá a seguinte saída:
all done.
Você pode ver esses artigos (1, 2) para uma explicação mais detalhada sobre por que isso não funciona. Por enquanto, lembre-se de evitar usar async/await dentro de um forEach!
Esquecer de usar .promise() no AWS-SDK
Você sabia que os clientes do AWS SDK oferecem suporte a retornos de chamada com promises? Para usar async/await no AWS SDK, adicione .promise() aos métodos do cliente:
const AWS = require('aws-sdk')
const Lambda = new AWS.Lambda()
async function invokeLambda(functionName) {
const req = {
FunctionName: functionName,
Payload: JSON.stringify({ message: 'hello world' })
}
await Lambda.invoke(req).promise()
}
Diga não aos callbacks, yay! 🎉
Finalizando
É isso aí! Esses são os erros mais comuns que podem ser evitados ao trabalhar com Node.js 8.10 em Lambda. Para obter mais dicas sobre como criar aplicativos serverless, escaláveis e prontos para produção, consulte o meu curso em vídeo! ;-)
Créditos ⭐️
- Common Node8 mistakes in Lambda, escrito originalmente por Yan Cui
Top comments (2)
E quando o time sobe um express centro de uma lambida :D heheeheh?
fala Rafa! :)
escrevi sobre isso no post anterior: dev.to/oieduardorabelo/6-coisas-qu...
no artigo, a camada intermediária era Node/Express, simplesmente pela familiaridade ai começar a migração para serverless
mas não é necessário, e para uma execução mais rápida da sua Lambda, eu recomendo você podar suas dependências e delegar roteamento para o AWS API Gateway,
vou compartilhar mais sobre no futuro :)