6.3 KiB
title | localeTitle |
---|---|
Promises | Promessas |
Promessas
JavaScript é single threaded, o que significa que dois bits de script não podem ser executados ao mesmo tempo; eles têm que correr um após o outro. Um Promise é um objeto que representa a conclusão (ou falha) final de uma operação assíncrona e seu valor resultante.
var promise = new Promise(function(resolve, reject) {
// do thing, then…
if (/* everything worked */) {
resolve("See, it worked!");
}
else {
reject(Error("It broke"));
}
});
Uma Promessa existe em um desses estados
- Pendente: estado inicial, nem cumprido nem rejeitado.
- Cumprida: operação concluída com sucesso.
- Rejeitado: falha na operação.
O objeto Promise funciona como proxy para um valor não necessariamente conhecido quando a promessa é criada. Ele permite que você associe os manipuladores ao valor de sucesso ou motivo de falha de uma ação assíncrona. Isso permite que os métodos assíncronos retornem valores como métodos síncronos: em vez de retornar imediatamente o valor final, o método assíncrono retorna uma promessa de fornecer o valor em algum momento no futuro.
Usando 'Then' (Promise Chaining)
Para fazer várias chamadas assíncronas e sincronizá-las uma após a outra, você pode usar o encadeamento de promessas. Isso permite usar um valor da primeira promessa em retornos de chamada posteriores subsequentes.
Promise.resolve('some')
.then(function(string) { // <-- This will happen after the above Promise resolves (returning the value 'some')
return new Promise(function(resolve, reject) {
setTimeout(function() {
string += 'thing';
resolve(string);
}, 1);
});
})
.then(function(string) { // <-- This will happen after the above .then's new Promise resolves
console.log(string); // <-- Logs 'something' to the console
});
API Promise
Existem 4 métodos estáticos na classe Promise:
- Promise.resolve
- Promise.reject
- Promise.all
- Promise.race
Promessas podem ser encadeadas
Ao escrever Promessas para resolver um problema em particular, você pode encadear as mesmas para formar a lógica.
var add = function(x, y) {
return new Promise((resolve,reject) => {
var sum = x + y;
if (sum) {
resolve(sum);
}
else {
reject(Error("Could not add the two values!"));
}
});
};
var subtract = function(x, y) {
return new Promise((resolve, reject) => {
var sum = x - y;
if (sum) {
resolve(sum);
}
else {
reject(Error("Could not subtract the two values!"));
}
});
};
// Starting promise chain
add(2,2)
.then((added) => {
// added = 4
return subtract(added, 3);
})
.then((subtracted) => {
// subtracted = 1
return add(subtracted, 5);
})
.then((added) => {
// added = 6
return added * 2;
})
.then((result) => {
// result = 12
console.log("My result is ", result);
})
.catch((err) => {
// If any part of the chain is rejected, print the error message.
console.log(err);
});
Isso é útil para seguir um paradigma de programação funcional . Criando funções para manipulação de dados você pode encadear-los juntos para montar um final resultado. Se em algum ponto da cadeia de funções um valor for rejeitado, a cadeia irá pular para o manipulador catch()
mais próximo.
Para mais informações sobre Programação Funcional : Programação Funcional
Geradores de Função
Em versões recentes, o JavaScript introduziu mais maneiras de lidar com o Promises de maneira nativa. Uma dessas maneiras é o gerador de funções. Geradores de funções são funções "pausáveis". Quando usados com o Promises, os geradores podem tornar o uso muito mais fácil de ler e parecer "síncrono".
const myFirstGenerator = function* () {
const one = yield 1;
const two = yield 2;
const three = yield 3;
return 'Finished!';
}
const gen = myFirstGenerator();
Aqui está nosso primeiro gerador, que você pode ver pela function*
syntax. A variável gen
que declaramos não rodará myFirstGenerator
, mas sim "este gerador está pronto para uso".
console.log(gen.next());
// Returns { value: 1, done: false }
Quando gen.next()
ele irá interromper o gerador e continuar. Como esta é a primeira vez que chamamos gen.next()
ele executará o yield 1
e fará yield 1
pausa até chamarmos gen.next()
novamente. Quando o yield 1
é chamado, ele retornará para nós o value
que foi gerado e se o gerador está ou não done
.
console.log(gen.next());
// Returns { value: 2, done: false }
console.log(gen.next());
// Returns { value: 3, done: false }
console.log(gen.next());
// Returns { value: 'Finished!', done: true }
console.log(gen.next());
// Will throw an error
Conforme continuamos chamando gen.next()
ele continuará indo para o próximo yield
e pausando a cada vez. Uma vez que não há mais yield
, ele continuará a executar o restante do gerador, que neste caso simplesmente retorna 'Finished!'
. Se você chamar gen.next()
novamente, ele lançará um erro quando o gerador terminar.
Agora, imagine se cada yield
deste exemplo fosse uma Promise
, o próprio código pareceria extremamente síncrono.
Promise.all (iterável) é muito útil para vários pedidos para diferentes fontes
O método Promise.all (iterável) retorna um único Promise que resolve quando todas as promessas no argumento iterável foram resolvidas ou quando o argumento iterável não contém promessas. Ele rejeita com a razão da primeira promessa que rejeita.
var promise1 = Promise.resolve(catSource);
var promise2 = Promise.resolve(dogSource);
var promise3 = Promise.resolve(cowSource);
Promise.all([promise1, promise2, promise3]).then(function(values) {
console.log(values);
});
// expected output: Array ["catData", "dogData", "cowData"]
Mais Informações
Para mais informações sobre promessas: Promessas