As promessas têm estado, elas começam como pendentes e podem resolver:
- realizada o que significa que o cálculo foi concluído com êxito.
- rejeitado o que significa que a computação falhou.
As funções de retorno promissor nunca devem ser lançadas ; elas devem retornar rejeições. O lançamento de uma função de retorno de promessa forçará você a usar os modos a } catch {
e a .catch
. As pessoas que usam APIs prometidas não esperam que as promessas sejam lançadas. Se você não tem certeza de como as APIs assíncronas funcionam em JS - consulte esta resposta primeiro.
1. Carregamento do DOM ou outro evento único:
Portanto, criar promessas geralmente significa especificar quando elas se estabelecem - ou seja, quando elas passam para a fase cumprida ou rejeitada para indicar que os dados estão disponíveis (e podem ser acessados com .then
).
Com implementações de promessa modernas que suportam o Promise
construtor como as promessas nativas do ES6:
function load() {
return new Promise(function(resolve, reject) {
window.onload = resolve;
});
}
Você usaria a promessa resultante da seguinte maneira:
load().then(function() {
// Do things after onload
});
Com bibliotecas que suportam adiado (Vamos usar $ q para este exemplo aqui, mas também usaremos o jQuery posteriormente):
function load() {
var d = $q.defer();
window.onload = function() { d.resolve(); };
return d.promise;
}
Ou com uma jQuery como API, conectando-se a um evento que acontece uma vez:
function done() {
var d = $.Deferred();
$("#myObject").once("click",function() {
d.resolve();
});
return d.promise();
}
2. Retorno de chamada simples:
Essas APIs são bastante comuns, pois bem ... retornos de chamada são comuns em JS. Vejamos o caso comum de ter onSuccess
e onFail
:
function getUserData(userId, onLoad, onFail) { …
Com implementações de promessa modernas que suportam o Promise
construtor como as promessas nativas do ES6:
function getUserDataAsync(userId) {
return new Promise(function(resolve, reject) {
getUserData(userId, resolve, reject);
});
}
Com bibliotecas que suportam adiado (Vamos usar jQuery para este exemplo aqui, mas também usamos $ q acima):
function getUserDataAsync(userId) {
var d = $.Deferred();
getUserData(userId, function(res){ d.resolve(res); }, function(err){ d.reject(err); });
return d.promise();
}
O jQuery também oferece um $.Deferred(fn)
formulário, que tem a vantagem de nos permitir escrever uma expressão que emula muito de perto o new Promise(fn)
formulário, da seguinte maneira:
function getUserDataAsync(userId) {
return $.Deferred(function(dfrd) {
getUserData(userId, dfrd.resolve, dfrd.reject);
}).promise();
}
Nota: Aqui exploramos o fato de que os métodos resolve
e reject
métodos adiados por jQuery são "destacáveis"; ie eles estão ligados à instância de um jQuery.Deferred (). Nem todas as bibliotecas oferecem esse recurso.
3. Retorno de chamada no estilo do nó ("nodeback"):
Os retornos de chamada no estilo do nó (nodebacks) têm um formato específico em que os retornos de chamada são sempre o último argumento e seu primeiro parâmetro é um erro. Vamos primeiro promisificar um manualmente:
getStuff("dataParam", function(err, data) { …
Para:
function getStuffAsync(param) {
return new Promise(function(resolve, reject) {
getStuff(param, function(err, data) {
if (err !== null) reject(err);
else resolve(data);
});
});
}
Com adiados, você pode fazer o seguinte (vamos usar Q neste exemplo, embora Q agora suporte a nova sintaxe que você preferir ):
function getStuffAsync(param) {
var d = Q.defer();
getStuff(param, function(err, data) {
if (err !== null) d.reject(err);
else d.resolve(data);
});
return d.promise;
}
Em geral, você não deve prometer demais as coisas manualmente, a maioria das bibliotecas promissoras que foram projetadas com o Node em mente, assim como as promessas nativas no Nó 8+, têm um método interno para prometer nodebacks. Por exemplo
var getStuffAsync = Promise.promisify(getStuff); // Bluebird
var getStuffAsync = Q.denodeify(getStuff); // Q
var getStuffAsync = util.promisify(getStuff); // Native promises, node only
4. Uma biblioteca inteira com retornos de chamada no estilo do nó:
Não há regra de ouro aqui, você as promete uma a uma. No entanto, algumas implementações promissoras permitem fazer isso em massa, por exemplo, no Bluebird, converter uma API nodeback em uma API promissora é tão simples quanto:
Promise.promisifyAll(API);
Ou com promessas nativas no Node :
const { promisify } = require('util');
const promiseAPI = Object.entries(API).map(([key, v]) => ({key, fn: promisify(v)}))
.reduce((o, p) => Object.assign(o, {[p.key]: p.fn}), {});
Notas:
- Obviamente, quando você está em um
.then
manipulador, não precisa promisificar as coisas. O retorno de uma promessa de um .then
manipulador resolverá ou rejeitará o valor dessa promessa. Jogando de um.then
manipulador também é uma boa prática e rejeitará a promessa - esta é a famosa promessa de lance de segurança.
- Em um
onload
caso real , você deve usar em addEventListener
vez de onX
.