Obtendo Resultados de Promises em JavaScript
Anteriormente, exploramos como, a partir de uma função promise, podemos passar para fora o resultado de uma operação assíncrona:
const myPromise = new Promise(function (resolve) {
console.log("Executando a operação assíncrona");
resolve("Olá mundo!");
});
Agora, vamos obter esse valor. Para receber o resultado de uma operação de promise, usamos a função then()
do objeto Promise
:
then(onFulfilled, onRejected);
O primeiro parâmetro da função, onFulfilled
, representa a função que é executada quando a promise é resolvida com sucesso e recebe os dados passados em resolve()
.
O segundo parâmetro, onRejected
, representa a função que é executada em caso de erro e recebe os dados passados em reject()
.
A função then()
também retorna um objeto Promise
.
Assim, podemos obtemos os dados:
const myPromise = new Promise(function (resolve) {
console.log("Executando a operação assíncrona");
resolve("Olá mundo!");
});
myPromise.then(function (value) {
console.log(`Dados recebidos da promise: ${value}`);
});
O parâmetro value
aqui representará a string "Olá mundo!", que é passada em resolve("Olá mundo!")
. Consequentemente, a saída no console será:
Executando a operação assíncrona Dados recebidos da promise: Olá mundo!
Para exemplificar, vamos chamar várias promises para ver a assincronia em ação:
const myPromise3000 = new Promise(function (resolve) {
console.log("[myPromise3000] Executando a operação assíncrona");
setTimeout(() => {
resolve("[myPromise3000] Olá mundo!");
}, 3000);
});
const myPromise1000 = new Promise(function (resolve) {
console.log("[myPromise1000] Executando a operação assíncrona");
setTimeout(() => {
resolve("[myPromise1000] Olá mundo!");
}, 1000);
});
const myPromise2000 = new Promise(function (resolve) {
console.log("[myPromise2000] Executando a operação assíncrona");
setTimeout(() => {
resolve("[myPromise2000] Olá mundo!");
}, 2000);
});
myPromise3000.then((value) => console.log(value));
myPromise1000.then((value) => console.log(value));
myPromise2000.then((value) => console.log(value));
Aqui, definimos três promises idênticas. Cada uma não é executada imediatamente, utilizando a função setTimeout
e definindo o valor retornado apenas após alguns segundos. Os tempos de atraso são diferentes para cada promise. Neste caso, a saída no console será:
[myPromise3000] Executando a operação assíncrona [myPromise1000] Executando a operação assíncrona [myPromise2000] Executando a operação assíncrona [myPromise1000] Olá mundo! [myPromise2000] Olá mundo! [myPromise3000] Olá mundo!
Observamos que o primeiro a iniciar foi o myPromise3000
, mas ele terminou por último devido ao maior tempo de atraso estabelecido, 3 segundos. No entanto, esse atraso não impediu a execução das outras promises.
Além disso, não é necessário passar um valor em resolve()
. A operação assíncrona pode simplesmente ocorrer sem retornar um valor:
const x = 4;
const y = 8;
const myPromise = new Promise(function () {
console.log("Executando a operação assíncrona");
const z = x + y;
console.log(`Resultado da operação: ${z}`);
});
myPromise.then();
Neste caso, a função na promise calcula a soma dos números x
e y
e imprime o resultado no console.
Método Promise.resolve
Às vezes, é necessário simplesmente retornar um valor de uma promise. Para isso, pode-se usar o método Promise.resolve()
. Este método recebe o valor a ser retornado pela promise e devolve um objeto Promise
:
const myPromise = Promise.resolve("Olá mundo!");
myPromise.then((value) => console.log(value)); // Olá mundo!
Definindo uma Promise por Meio de uma Função
Frequentemente, uma promise é definida por uma função que retorna um objeto Promise
. Por exemplo:
function sum(x, y) {
return new Promise(function (resolve) {
const result = x + y;
resolve(result);
});
}
sum(3, 5).then(function (value) {
console.log("Resultado da operação:", value);
});
sum(25, 4).then(function (value) {
console.log("Soma dos números:", value);
});
A função sum()
recebe dois números e retorna uma promise que encapsula a operação de soma desses números. Após o cálculo, a soma é passada para resolve()
, e então podemos obter o resultado por meio do método then()
. Definir uma promise através de uma função nos permite, por um lado, passar diferentes valores ao chamar a função. Por outro lado, tratamos o resultado dessa função como uma promise e configuramos o tratamento do valor recebido para cada chamada específica.
O resultado:
Resultado da operação: 8 Soma dos números: 29
Mas, e se o princípio de tratamento do valor obtido da função assíncrona for o mesmo?
sum(3, 5).then(function (value) {
console.log("Resultado da operação:", value);
});
sum(25, 4).then(function (value) {
console.log("Resultado da operação:", value);
});
Nesse caso, a lógica de tratamento será repetida. Como o método then()
também retorna um objeto Promise, podemos proceder da seguinte forma:
function sum(x, y) {
return new Promise(function (resolve) {
const result = x + y;
resolve(result);
}).then(function (value) {
console.log("Resultado da operação:", value);
});
}
sum(3, 5);
sum(25, 4);
Configuração Flexível da Função
E se quisermos que o programador tenha a opção de definir seu próprio manipulador, ou, se ele preferir, aplicar um manipulador padrão? Neste caso, podemos definir a função do manipulador como um parâmetro da função e, se não for fornecido, definir um manipulador padrão:
function sum(x, y, func) {
// se não for definido um manipulador, então definimos um manipulador padrão
if (func === undefined)
func = function (value) {
console.log("Resultado da operação:", value);
};
return new Promise(function (resolve) {
const result = x + y;
resolve(result);
}).then(func);
}
sum(3, 5);
sum(25, 4, function (value) {
console.log("Soma:", value);
});
Aqui, na primeira chamada da função sum(3, 5)
, será utilizado o manipulador padrão function(value) { console.log("Resultado da operação:", value); }
. No segundo caso, o manipulador é explicitamente passado por meio do terceiro parâmetro, portanto, será usado function(value) { console.log("Soma:", value); }
.