Promises

Promise é uma API nativa JavaScript (ECMAScript 6) que segue a especificação Promises/A+, É um recurso que já está disponível nos navegadores modernos (menos na droga do IE é claro), e também algumas das novas API que estão sendo padronizadas no W3C. Realmente é algo que todo desenvolvedor deve aprender. Só pra ter uma noção da importância do uso de Promises, segue uma pequena relação das novas APIs que estão nas especificações do W3C/WHATWG que já implementam Promise:

O principal objetivo do uso de Promise é trabalhar com operações assíncronas, mas de maneira diferente da qual normalmente nos estamos acostumados. Normalmente quando lidamos com operações assíncronas, utilizamos funções callbacks para tratar as ações de um determinado resultado. As vezes precisamos de ações assíncronas que dependem da resposta de outra operação assíncrona para poder continuar, podendo levar o código a ter callbacks dentro de callbacks, o que não fica legal na hora de dar manutenção no código. Veja um exemplo de callbacks dentro de callbacks:
Com Promise você pode evitar ter tantos callbacks dentro de callbacks e seu código ficará mais limpo, de fácil leitura, padronizado, com um fluxo de execução mais intuitivo e mais consistente além de um controle de erro mais organizado.
Uma Promise representa o eventual resultado de uma operação assíncrona, onde você pode delegar múltiplas funções de sucesso ou erro para lidar com o resultado da operação assíncrona que pode ser um resultado resolvido com sucesso ou rejeitado com algum erro.
A promise pode ter estes status:
  • fulfilled foi resolvida com sucesso
  • rejected foi rejeitada por alguma razão
  • pending status inicial ainda não foi resolvida/rejeitada
  • settled já foi finalizada sendo resolvida ou rejeitada
Uma Promise finalizada só pode ser resolvida ou rejeitada e nunca assumir os dois status, ou seja, o primeiro que for setado será o status final, logo somente as funções(métodos) de sucesso ou erros serão executas e não as duas. Após finalizada, uma promise nunca mudará seu status.

Conhecendo um pouco a API

Construtor

O construtor Promise recebe uma function que possui dois parametros 'resolve' e 'reject' que são as functions que resolverão a promise, para resolver com sucesso use a function 'resolve' caso queira rejeitar com erro use 'reject'.
Observações: caso ocorra uma Exception dentro da function do construtor Promise, a promise será rejeitada automaticamente, caso chame resolve com um valor que seja uma Promise, então a promise atual respeitará a finalização da promise enviada no resolve, e assim por diante.

Métodos

  • Método then:
    O método then é o cara onde nos registraremos as funções de sucesso(onResolve) ou de erro(onReject) da promise. Ele possui dois parâmetros:
    • onResolve: é a function que será executada quando a promise for finalizada com sucesso(quando chamamos o resolve). onResolve recebe como parâmetro o valor resolvido na promise.
    • onReject: é a function que será executada quando a promise for rejeitada por algum motivo(quando chamamos o reject ou ocorreu uma Exception). onReject recebe como parâmetro o motivo do erro.
    Tanto onResolve como onReject são executadas com o contexto vazio, logo o this delas é undefined (no modo strict).
    O método then pode ser chamado várias vezes, logo podemos registrar várias funções de sucesso e erro, sendo que elas serão chamadas na ordem em que foram registradas.
    O then retorna uma nova instância de Promise (vamos chamar de B), B será resolvida quando a Promise anterior(a que chamou then que gerou a Promise B) for finalizada, seja no onResolve ou no onReject, considerando a mesma regra de resolução de uma Promise, caso onResolve ou onReject gere um Exception, B será rejeitada, caso retorne um valor que não seja uma Promise, B será resolvida com sucesso, caso retorne uma nova Promise C a Promise B respeitará a finalização desta nova Promise C retornada, e assim sucessivamente gerando um encadeamento de Promises.
    Observação: no encadeamento das Promises caso uma Promise subsequente não registre onResolve ou onReject a finalização será passada para a próxima Promise que registrou(onResolve ou onReject, de acordo com o resolução da Promise).

  • Método catch:
    O método catch é apenas uma atalho para Promise.prototype.then(undefined, onReject); ou seja é como se chama-se o then passando somente o onReject. Possui as mesmas regras do then.

Exemplo then/catch:


Métodos Estáticos

  • Método Promise.all(arrayPromises)
    Retorna uma Promise 'A' que é finalizada quando todas as Promises passadas em arrayPromises forem finalizadas, 'A' será resolvida com sucesso caso todas as arrayPromises sejam resolvidas com sucesso, caso alguma seja rejeitada a Promise 'A' será rejeitada também.
  • Método Promise.race(arrayPromises)
    Retorna uma Promise 'A' que é finalizada quando a primeira Promise passada em arrayPromises for finalizada, 'A' será finalizada conforme a Promise que foi finalizada em arrayPromises.
  • Método Promise.resolve(valor)
    Retorna uma Promise que é resolvida com valor.
    Caso o valor seja:
    • uma Promise, então esta será retornada
    • um objeto 'A' que possui método then, então retorna uma Promise que será resolvida de acordo com o then de 'A'.
    • um valor não-Promise, então retorna uma Promise resolvida com valor
  • Método Promise.reject(erro)
    Retorna uma Promise rejeitada com o erro.

Comparação Callbacks vs Promises

Como podemos ver, com Promise não precisamos ter callbacks dentro de callbacks, apenas podemos usar Promises encadeadas.
Veja uma comparação:

Exemplo usando ajax com Promise

Agora vou mostrar um exemplo de Ajax utilizando Promises, ajax é um cenário ideal para Promises ;)

Links para Aprender mais