[ Conteúdo ] Funções Assíncronas
Introdução:
Boa noite pessoal! Fazia um tempo que eu não aparecia, e recentemente tive uma ideia sobre um curto artigo sobre funções assíncronas no JavaScript, que é um tópico bastante importante dado a quantidade de posibilidades que Promises
nos proporciona na linguagem e seus derivados como fetch
e assim por diante.
Bom, não sei se tem algum artigo sobre aqui (perdão por não procurar antecipadamente). Se existir, encare isso como minha versão sobre o assunto. Dito isso, vamos para o que interessa.
Considerações:
Naturalmente, você deve dominar toda a base do JavaScript
, em especial entender como Promises
e functions
se comportam na linguagem.
Além disso, farei breve menções sobre tipagem, ou seja, envolve um pouco de TypeScript
, mas nada muito complexo.
O que são funções assíncronas?
O nome por si só já é bem sugestivo: São funções que lidam com operações assíncronas. Funções assíncronas nos permite escrever de maneira elegante e clara operações assíncronas ou lidar com operações assíncronas externas (retornada por outras funções).
Não é difícil criar uma função assíncrona, basta utilizar a palavra chave async
antes da palavra chave function
. Confuso? Então um breve exemplo:
async function MinhaFuncaoAssincrona() {
//...
}
Agora, tudo que eu faço dentro desde escopo se comporta como uma Promise
? A resposta é, não exatamente...
Assim como tudo na área de tecnologia, nada é tão simples assim, mas não é tão difícil, apenas existe o jeito certo de fazer as coisas. Funções assíncronas não param por aqui, tem mais features que ajudama a ter um comportamento melhor.
Mas, se você quer apenas um retorna de uma Promise
, então sim, o código acima retorna uma Promise
e mais abaixo eu explico em detalhes.
Palavra chave await
:
Quando declaramos uma função assíncrona, nos é permitido a utilização da palavra chave await
dentro de seu escopo.
E para que serve o await
, bom, aqui é que entra a mágica! A palavra chave await
basicamente diz que as operações abaixo devem esperar a operação que tem um await
para pode continuar. Confuso? O comportamento é igual ao padrão do JavaScript, ou seja, parece síncrono.
Então vamos tentar ilustrar melhor com um exemplo usando 2 fetch
:
const myFetch1 = fetch('url1');
const myFetch2 = fetch('url2');
async function MinhaFuncaoAssincrona() {
const first = await myFetch1.then(result => result.json());
const second = await myFetch2.then(result => result.json());
}
Acima, temos 2 fetch
que retornam uma Promise
, ou seja, uma operação de natureza assíncrona. Dento da função assíncrona, temos duas constante que convertem os resultados do fetch
para json
, mas aqui, a ordem é deterministica.
A constante second
vai esperar a constante first
para poder converter para json
. Simples, não? A operação ainda é assíncrona. Seu programa ou site não vai parar até esse primeiro fetch
ser convertido, apenas dentro deste escopo, dentro desta função assíncrona, controlamos a ordem das coisas.
Entender sobre concorrência
ajuda a entender com mais precisão sobre a ordem.
a ordem que os primeiro
fetch
são resolvidos é não deterministica. O que isso quer dizer? Quer dizer que não temos como saber qual vai ser resolvido primeiro. Entranto, oawait
controla a ordem em que eles são convertidos.
Sem await, não é assíncrono:
Na documentação deixa bem claro que uma função assíncrona, que não tenha nenhum await
nela é executada de forma síncrona:
async function HandleClick() {
// está função não é executada de forma assíncrona.
}
Além disso, você pode ter qualquer quantidade de await
em funções assíncrona, até zero, que cai no caso acima.
Funções assíncronas sempre retornam promises:
Sim, isto aqui é bem interessante. Independemente se o valor retornando não for uma Promise
, o valor será embrulhado em uma Promise
:
async function HandleMyAge(age) {
return age;
}
HandleMyAge(22) // Promise<number>
Isto aqui é mais evidente no TypeScript
, por isso que nunca usou pode não entender muito bem o que é Promise<number>
. Apenas saiba que é uma Promise
do tipo number
, de forma resumida :smile:
Voltando ao assunto: Funções assíncronas sempre retornam uma Promise
, mesmo quando não tem um return
explicitamente declarada. Funções que não tem return
, não retornam nada, ou seja, tem o tipo de retorno definido para void
. Entretando, em funções assíncronas, até esse void
é embrulhado em uma promise:
async function HandleVoid() {
// retorna Promise<void> que resolve para `undefined`
}
Isso pode abrir algumas possibilidades, pois mesmo resolvendo para undefined
, você pode encadear com o then
, dando que no fim, é uma Promise
.
async function HandleVoid() {
// retorna Promise<void> que resolve para `undefined`
}
HandleVoid()
.then(() => console.log("fazer algo"))
.then(() => console.log("fazer outra coisa"))
Conclusão:
EU diria que é um bom conteúdo introdutório sobre funções assíncronas, não? Na verdade, basicamente se resume a isto ai, não tem nada mais técnico sobre, além de técnicas em que funções assíncronas estão envolvidas ou nuances que diferem de caso para caso.
Então é isso, espero que tenham gostado.
Fiquei meio perdido, com await não era para ser síncrona?
cara, primeiro muito obrigado pelo post. Me veio uma dúvida aqui. você disse que uma função assíncrona sem await é uma função síncrona:
`async function HandleMyAge(age) { return age; }
HandleMyAge(22) // Promise`
O exemplo acima, do seu texto, retorna mesmo uma promise, ou no caso faltou declarar dessa forma:
`async function HandleMyAge(age) { await _age = age return _age }
HandleMyAge(22) // Promise`
Valeu mesmo por compartilhar seu conhecimento por aqui!
async/await e then/catch tem diferença importantes embora ambas lidem com promise. entender como cada uma funciona é muito importante.
um colega estava usando express e a função que lidava com requisição HTTP estava usando then/cath, e dentro deles estava retornando a response com os dados json. quem sabe do que estou falando sabe que a função handler vai retornar undefined igorando o return codado.