Image for post
Image for post
E aí, e esse exemplo ein?

A única coisa ruim sobre async/await do ES7

Eu venho usando e abusando do async/await em um projeto paralelo. Tem sido incrível a experiência com essa nova sintaxe e meu código se tornou mais conciso e ainda ganhou uma legibilidade maior! Se você já leu algum dos meus posts anteriores, você deve saber que eu sou um grande fã dessa abordagem. Entretanto, nem tudo são flores.

Eu percebi esse exemplo utilizando Async no Github ontem, que eu transcrevo aqui para vocês:

app.get('/', async (req, res, next) => {
let user = await User.findById(); // retorna uma Promise
let org = await Org.findById();
res.json({
user: user,
org: org,
});
});

Esse exemplo de código faz duas coisas; primeiro, ele localiza um usuário (possivelmente de algum banco de dados), e em seguida, localiza uma organização (também de algum lugar com resposta "lenta"), retornando os dois valores em uma resposta HTTP. Tudo isso sem usar callback. Uau! O código para realizar tudo isso acaba sendo bem pequeno e auto-explicável.

E ai vem a pergunta:

Você consegue encontrar o defeito?

As duas declarações await, ambas resultam em que a função seja "pausada" enquanto o resto da aplicação está livre para servir qualquer outra resposta para o usuário. Entretanto, o a declaração Org.findById(), não irá ser executada enquanto User.findById() não for completamente finalizado. Assumindo que ambas as operações levem 100ms para executar, o seu tempo de resposta é 200ms!

Ao aplicar a sintaxe async/await, que é fácil de usar, para executar trabalhos em série que poderiam ser paralelizados, nós estamos, parcialmente, abrindo mão daquilo que tornou o Node.js tão famoso; sua habilidade de realizar I/O em paralelo sem bloquear o event loop do JavaScript.

app.get('/', async (req, res, next) => {
let user = await User.findById(); // retorna uma Promise
let org = await Org.findById(user.orgId);

res.json({
user: user,
org: org,
});
});

Perceba como nós queremos que o segundo await ocorra depois do primeiro. Esse é um cenário perfeito para uso do async/await.

A única coisa ruim sobre async/await do ES7 é que é muito fácil de cairmos no anti-padrão de serializar os trabalhos que poderiam ser paralelizados.

Mas, como nós poderíamos escrever esse código, deixando-o conciso, auto-descrito e que execute em paralelo? Assumindo que User e Org utilizam uma API que retornam Promise, uma maneira de escrever isso seria utilizando o Promise.all() (veja mais sobre Promise.all() no MDN).

app.get(‘/’, async (req, res, next) => {
let [user, org] = await Promise.all([
User.findById(),
Org.findById()
]);
res.json({
user,
org
});
});

Claro que, o código não está tão expressivo como o anterior, mas, desde que Promise.all() retorna uma promise, nós podemos usar await nessa expressão e, assumindo que cada operação levará 100ms para finalizar, o usuário deve receber seus resultados em apenas 100ms.

Créditos

Written by

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store