Dúvida sobre funções assíncronas em Javascript
Estou aprendendo sobre funções assíncronas de forma meio "aleatória" pesquisando o conteúdo pela internet. Acabei ficando em dúvida porque, em todo conteúdo que encontro é apresentado isso de uma forma diferente. As vezes encontro nesse formato:
function minhaFuncao() {
return "Alguma coisa";
}
async function main() {
try {
const result = await minhaFuncao();
console.log(result);
} catch (error) {
console.error(error);
}
}
E as vezes encontro nesse formato:
function minhaFuncao() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Hello");
}, 2000);
});
}
minhaFuncao()
.then((result) => {
console.log(result);
})
.catch((error) => {
console.error(error);
});
A minha dúvida é: qual a diferença de escrever uma função com try/catch e uma promise com .then() e .catch()? Em que situação cada coisa é usada?
Quando vc usa o await
vc transforma sua função assíncrona em uma função síncrona.
Ou seja, o await
faz o programa esperar a resolução da Promise antes de continuar.
Ajustei os códigos que vc mostrou e preparei 2 exemplos para demonstrar a diferença.
EXEMPLO 1
function minhaFuncao() {
return new Promise((resolve) => setTimeout(() => resolve("Hello"), 2000));
}
console.log(new Date(), "Início");
minhaFuncao()
.then((result) => console.log(new Date(), result))
.catch((error) => console.error(new Date(), error));
console.log(new Date(), "Fim");
O resultado será parecido com este:
2024-04-07T14:22:29.815Z Início
2024-04-07T14:22:29.823Z Fim
2024-04-07T14:22:31.826Z Hello
Note que "Início" e "Fim" são impresso um logo após o outro enquanto que "Hello" só aparece 2 segundos depois.
É isso que a Promisse faz, executa uma tarefa fora do fluxo normal do programa.
EXEMPLO 2
function minhaFuncao() {
return new Promise((resolve) => setTimeout(() => resolve("Hello"), 2000));
}
console.log(new Date(), "Início");
const resultado = await minhaFuncao();
console.log(new Date(), resultado);
console.log(new Date(), "Fim");
O resultado será parecido com este:
2024-04-07T14:28:53.733Z Início
2024-04-07T14:28:55.743Z Hello
2024-04-07T14:28:55.743Z Fim
Aqui "Início" é impresso e 2 segundos depois vem "Hello" e por último "Fim".
Percebeu o que eu disse antes sobre o await
esperar a resolução da Promise antes de continuar o programa?
E sobre o try/catch
não tem segredo. É com essa duplinha que tratamos exceções no JavaScript.
Se vc estiver usando Promise, vc vai usar then/catch
, mas quando vc usa o await
, a Promise passa a se comportar como uma função síncrona e vc precisa usar try/catch
para tratar possíveis erros.
Sobre quando vc deve usar cada uma, acredito que o ideal é modelar o seu programa todo de forma assíncrona pra tirar total proveito das Promise, mas pode haver situações em que isso não é possível, ou então vc sabe que a tarefa que a Promise vai realizar é tão simples e rápida que vale a pena esperar.
Olha vc esta aprendendo os conceitos de maneira inversa. O correto seria:
- Calbacks
- Promises
- Async await
Esta ordem tem motivos. Pois uma vem depois da outra!
Se quiser entender melhor tem estes artigos que falam de cada uma delas na ordem!
Opa tudo bem Bruno? Seguinte, eu tecnicamente aprendi async/await na marra sem ordem nem nada, não estou dizendo que é o certo. Portanto, a diferença entre promise e try/catch, funcionalmente são a mesma coisa, mas a promise se torna um pouco diferente.
Try/catch
Esse método, ele é utilizado em casos sincronos onde não há a utilização de async/await, mas nada diz que você precisa utilizar esse método só nessa situação. No exemplo abaixo explico como funciona o resultado da função.
async function hello_world() {
try {
const request = await _api-response_
return request;
} catch (error) {
return error;
}
}
Nessa função, o resultado produzido será um return com os dados esperados - se der certo - ou um resultado com os erros. Se o resultado for o esperado e você, por exemplo receber um json, você conseguirá acessar o json sem precisar realizar outro passo, nesse caso, um .then que é necessário quando se tem uma promise sem async/await.
Promise
Essencialmente a ideia é a mesma que o try/catch, mas esse método é utilizado e recomendado para funções assíncronas como em apis próprias. Normalmente se pode utilizar sem a necessidade async/await, mas você precisará encadear estruturas .then/.catch para saber os resultados.
function minhaFunçao() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Hello");
}, 2000);
});
minhaFuncao()
.then((result) => {
console.log(result);
})
.catch((error) => {
console.error(error);
});
Neste exemplo, se você colocar a função (minhaFuncao) em um console, você perceberá que será mostrado: "Promise {<pending}". Nesse caso você não consegue saber o retorno da função, para saber você precisa realizar a estrutura de .then que mostra o resultado da promise. Entretanto, você pode evitar esse passos a mais utilizando o async/await para dizer ao request que você pode esperar as promises se resolverem e trazer o resultado esperado, sem a necessidade de fazer o .then/.catch.
Quando utilizar um ou outro?
Resumidamente, utiliza-se o método try/catch em situações síncronas que podem gerar erros que você queira tratar. Já a promise é utilizada, comumente, para funções assíncronas. Ou seja, essencialmente são a mesma coisa, são estruturas para tratar resultados diferentes, mas são utilizadas em contextos diferentes, como em contextos síncronos (try/catch) e assíncronos (promises). No fim, você pode utilizar try/catch em situações assícronas e promises em situações sincronas ou vice e versa, mas a utilizacão de promises em contextos assíncronos, torna a leitura do código mais limpa e clara demonstrando organização de código a outros programadores.