JavaScript Promise: do que se trata?
O Promise é uma funcionalidade nativa do JavaScript 6 (ECMA 2015) para tratar requisições assíncronas e/ou demoradas.
Quando precisamos realizar chamadas que podem resultar nos dados esperados ou erros, normalmente utilizamos eventos ou callbacks.
Por exemplo,
let imagem_principal = document.querySelector('.img_principal');
imagem_principal.addEventListener('load', function() {
// faz alguma coisa quando a imagem principal é carregada
});
imagem_principal.addEventListener('error', function() {
// realiza algo quando acontece algum erro ocorre
});
No exemplo acima é possível que algum evento ocorra antes de criarmos os listeners da imagem.
Para contornar isso, podemos utilizar a propriedade “complete” da imagem para sabermos que ela foi carregada:
let imagem_principal = document.querySelector('.img_principal');
function carregada(){
// faz alguma coisa quando a imagem principal é carregada
}
if(imagem_principal.complete){
carregada();
} else {
imagem_principal.addEventListener('load', carregada);
}
imagem_principal.addEventListener('error', function() {
// realiza algo quando acontece algum erro ocorre
});
Porém essa aproximação também não captura erros de carregamento da imagem antes de criarmos o listener. Isso pode ser mais complicado ainda se precisarmos saber se um conjunto de imagens foram carregadas corretamente e se alguma exibiu erro.
Eventos não são o melhor caminho
Eventos são muito bons quando algo pode acontecer várias vezes no mesmo objeto tipo keypress, mousever etc. Nesses eventos não precisamos nos importar com o que aconteceu com o objeto antes de anexarmos o listener. Mas quando precisamos de acesso assíncrono com possibilidade de sucesso/erro, precisaríamos algo do tipo:
imagem1.executeIstoSeOuQuandoCarregado(function(){
// imagem carregada
}).seErroChamaIsto(function(){
// erro
});
// ...
quandoCarregarTodasImagens([imagem1, imagem2, imagem3]).executeIssso(function(){
// todas as imagens carregadas
}).seAlgumaFalhouExecuteIsso(function(){
// alguma falhou
});
Isto é exatamente o que uma Promise faz mas com os nomes dos métodos mais padronizados que esses.
Se o elemento imagem do HTML possuísse o método “ready” que retornasse um Promise poderíamos fazer da seguinte forma:
imagem1.ready().then(function(){
// carregada
}, function(){
// erro
});
// ...
Promise.all([imagem1.ready(), imagem2.ready(), imagem3.ready()]).then(function(){
// todas imagens carregadas
}, function(){
// alguma deu erro
});
Estados de um Promise
Uma Promise possui alguns estados mutualmente exclusivos:
– pendente: estado inicial, ainda não concluído ou rejeitado.
– realizada: sucesso na operação
– rejeitado: falha na operação.
– determinado: a Promise ou está realizada ou rejeitada, mas não pendente.
Utilizando uma Promise
Para utilizarmos uma Promise, temos que defini-la e chama-la posteriormente:
let promise = new Promise(function(resolve, reject) {
// fazer algo assíncrono...
if (/* retorno positivo */) {
resolve("Funcionou!");
} else {
reject(Error("melou..."));
}
});
O construtor da Promise tem apenas um argumento, um callback com dois parâmetros, um quando executa corretamente “resolve” e outro quando ocorre algum erro “reject”. Ao fazer algo assíncrono com um callback dentro da Promise, se deu certo, chamamos o “resolve” caso contrário “reject”.
É como o “throw” no JavaScript, é utilizado mas não é obrigatório rejeitar com um objeto Error. Mas o bom de se utilizar o objeto Error é que ele captura o trace do erro facilitando assim o debug.
A Promise acima foi definida e abaixo seria sua utilização:
promise.then(function(result) {
console.log(result); // exibe: "Funcionou!"
}, function(err) {
console.log(err); // exibe: Error: "melou..."
});
Mais informmações
https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Promise
https://spring.io/understanding/javascript-promises
http://www.mattgreer.org/articles/promises-in-wicked-detail/
Se houver alguma dúvida, sugestão ou percebeu algum erro de digitação, não hesite em entrar em contato que responderei tão rápido quanto puder e atribuirei o crédito pela ajuda.
Até mais!
André Fellows