Introdução às Promises em JavaScript
Uma promise é um objeto que representa o resultado, seja bem-sucedido ou falho, de uma operação assíncrona. Simplificadamente, uma operação assíncrona é uma ação que ocorre independentemente do código ao seu redor, sem bloquear a execução desse código.
Uma promise pode estar em um dos seguintes estados:
pending
(estado de espera): estado inicial, a promise foi criada, mas a execução ainda não foi concluída.fulfilled
(concluído com sucesso): a ação que a promise representa foi concluída com sucesso.rejected
(concluído com erro): ocorreu um erro durante a execução da ação que a promise representa.
Para criar uma promise, usa-se o construtor Promise
:
new Promise(executor);
O construtor recebe uma função que é executada imediatamente ao criar a promise. Essa função geralmente representa operações assíncronas que podem levar algum tempo. Por exemplo, vamos definir uma promise muito simples:
const myPromise = new Promise(function () {
console.log("Executando operação assíncrona");
});
Neste caso, a função apenas exibe uma mensagem no console. Assim, ao executar este código, veremos a mensagem "Executando operação assíncrona" no console.
Quando uma promise é criado e sua função ainda não começou a ser executada, a promise entra no estado "pending", ou seja, aguarda a execução.
Para simular a assincronicidade, vamos definir vários promises:
const myPromise3000 = new Promise(function () {
console.log("[myPromise3000] Executando operação assíncrona");
setTimeout(() => console.log("[myPromise3000] Conclusão da operação assíncrona"), 3000);
});
const myPromise1000 = new Promise(function () {
console.log("[myPromise1000] Executando operação assíncrona");
setTimeout(() => console.log("[myPromise1000] Conclusão da operação assíncrona"), 1000);
});
const myPromise2000 = new Promise(function () {
console.log("[myPromise2000] Executando operação assíncrona");
setTimeout(() => console.log("[myPromise2000] Conclusão da operação assíncrona"), 2000);
});
Aqui são definidos três promises idênticos. Para que cada um deles não seja executado imediatamente, eles usam a função setTimeout
com um delay de alguns segundos. A duração do delay varia para diferentes promises. Neste caso, obteremos a seguinte saída no console:
[myPromise3000] Executando operação assíncrona [myPromise1000] Executando operação assíncrona [myPromise2000] Executando operação assíncrona [myPromise1000] Conclusão da operação assíncrona [myPromise2000] Conclusão da operação assíncrona [myPromise3000] Conclusão da operação assíncrona
Aqui, vemos que a primeira a começar a execução foi a promise myPromise3000
, mas ela também foi a última a terminar, pois tinha o maior tempo de delay, 3 segundos. No entanto, esse delay não impediu a execução das outras promises.
resolve e reject
Normalmente, a função passada ao construtor Promise aceita dois parâmetros: resolve
e reject
, ambos também funções, que podem aceitar um argumento de qualquer tipo.
- Função
resolve
: chamada em caso de sucesso, pode receber um valor que será obtido como resultado da execução bem-sucedida. - Função
reject
: chamada em caso de erro, pode receber um valor que representará alguma informação sobre o erro.
Execução Bem-Sucedida do Promise
Portanto, o primeiro parâmetro da função no construtor do Promise, a função resolve
, é executada quando a operação é concluída com sucesso. Geralmente, passa-se para essa função um valor que representa o resultado da operação bem-sucedida. Esse valor pode ser qualquer objeto. Por exemplo, vamos passar uma string para essa função:
const myPromise = new Promise(function (resolve) {
console.log("Executando operação assíncrona");
resolve("Olá mundo!");
});
A função resolve()
é chamada no final da operação, após todas as ações terem sido realizadas. Ao chamar essa função, a promise muda para o estado fulfilled
(concluído com sucesso).
É importante notar que, teoricamente, podemos retornar um resultado diretamente da função, mas isso não teria sentido prático:
const myPromise = new Promise(function (resolve, reject) {
console.log("Executando operação assíncrona");
return "Olá mundo!";
});
Esse valor retornado não pode ser passado para fora. E se realmente precisarmos retornar algum resultado, ele deve ser passado através da função resolve
.
Informação sobre Erro
O segundo parâmetro da função no construtor do Promise, a função reject
, é chamada quando ocorre um erro. Normalmente, passa-se para essa função alguma informação sobre o erro, que pode ser qualquer objeto. Por exemplo:
const myPromise = new Promise(function (resolve, reject) {
console.log("Executando operação assíncrona");
reject("Dados incorretos fornecidos");
});
Ao chamar a função reject()
, a promise muda para o estado rejected
(concluído com erro).
Combinação de resolve e reject
Podemos definir uma lógica na qual, dependendo das condições, ambas as funções são executadas:
const x = 4;
const y = 0;
const myPromise = new Promise(function (resolve, reject) {
if (y === 0) {
reject("Dados incorretos");
} else {
const z = x / y;
resolve(z);
}
});
Nesse caso, se o valor da constante y for 0, reportamos um erro chamando a função reject
. Se for diferente de 0, realizamos uma operação de divisão e passamos o resultado para a função resolve
.