Promises
Motivação
Até agora consideramos que as funções assíncronas sempre serão bem-sucedidas em suas respectivas tarefas. Na prática, erros podem acontecer. Por exemplo, uma função que faz o download de um arquivo pode falhar porque o servidor está fora do ar ou muito lento; nesse caso, a função deve indicar o erro ao código que a chamou.
Um padrão comum para possibilitar o tratamento de erros em funções assíncronas é usar dois callbacks: um que será chamado em caso de sucesso, e o outro que será chamado em caso de erro.
No exemplo abaixo, a função assíncrona sorteia0
retorna um número aleatório entre 0 e maximo
, mas tem 20% de chance de falhar. Ela recebe dois callbacks: a função resolve
, que será chamada em caso de sucesso, e a função reject
, que será chamada em caso de falha.
Se quisermos agora encadear uma sequência de sorteios, de tal forma que um sorteio só inicie quando o sorteio anterior for concluído com sucesso, o código tende a ficar difícil de ler e entender.
Promises
Promises são objetos (da classe Promise
) que encapsulam uma chamada a uma função assíncrona que possui callbacks de sucesso e erro.
(Um conceito relacionado é o de future, presente em outras linguagens de programação.)
Uma promise pode estar em um dos seguintes estados:
- pendente: a operação ainda não foi finalizada
- resolvida: a operação foi finalizada com sucesso
- rejeitada: a operação foi finalizada com erro
Uma promise que se encontra no estado resolvida ou rejeitada (isto é, não está pendente) é dita estabelecida.
Podemos reescrever a função assíncrona sorteia
de forma que ela retorne uma promise. O código que usa a função deve então chamar os métodos then()
e catch()
da classe Promise
para tratar o resultado:
then(f)
recebe uma função,f
que deve ser executada quando a promise é resolvidacatch(f)
recebe uma função,f
que deve ser executada quando a promise é rejeitada- Tanto
then(f)
quantocatch(f)
retornam uma promise que será resolvida com o valor retornado porf
.
Execute o código a seguir para carregar a função sorteia
, que será usada nos outros exemplos.
Execução sequencial de promises
Como o then()
retorna uma promise, você pode encadear chamadas a then()/catch()
, que serão executadas de forma sequencial:
Execução paralela de promises: Promise.all
Promise.all
recebe um array de promises e cria um novo promise que termina somente quando todos os promises da array terminam. Em outras palavras, Promise.all
permite executar várias operações assíncronas em paralelo e executar alguma operação (usando o then()
) quando todas elas forem resolvidas. A função passada ao then()
recebe os valores de todos os promises em um array. Se alguma operação for rejeitada, a promise resultante também será rejeitada, imediatamente.
Execução paralela de promises: Promise.race
Assim como Promise.all
, Promise.race
também cria uma nova promise a partir de um array de promises, e permite executar as promises do array em paralelo. A diferença é que a nova promise é estabelecida (resolvida ou rejeitada) logo que qualquer promise do array for estabelecida.