AngularJS - misturando HTTP e promessas personalizadas com recursão
Eu escrevi um wrapper de função que retorna valores em cache para respostas HTTP. Em uma situação específica (marcada por comentário // <--HERE), vejo um comportamento inconsistente. Francamente, não tenho certeza do que exatamente é a inconsistência, mas no final das contas, quando o cache expira (has_expired), ele não espera que o http retorne na chamada recursiva.
Meu palpite é que não coloquei um "retorno" em alguma parte da promessa, mas não consigo descobrir onde (e por quê). Preciso colocar uma devolução antes de localForage.removeItem(e se sim, por quê?)
function cache_or_http(url,key) {
if (dont_use_cache()) {
return $http.get(url); } var d = $q.defer();
localforage.getItem(key)
.then (function(data) {
if (data) { // exists
if (has_expired(data.created_at)) {
localforage.removeItem(key)
.then (function() {return cache_or_http(url,key);}) // <--HERE
.catch(function() {return do_error_handling();})
} else { // not expired
d.resolve(JSON.parse(data.value));
return d.promise;
}
} else {
// doesn't exist
return $http.get(url)
.then (function(data) {
cache_entry = {
'value': JSON.stringify(data),
'created_at': moment().toString()
};
localforage.setItem(key, cache_entry);
d.resolve(data);
return (d.promise);
});
} // doesn't exist
}); // getItem .then
return (d.promise);
}
Respostas
Não há necessidade de fabricar uma nova promessa com $q.defer. O .thenmétodo de uma promessa já retorna uma promessa.
function cache_or_http(url,key) {
̶v̶a̶r̶ ̶d̶ ̶=̶ ̶$̶q̶.̶d̶e̶f̶e̶r̶(̶)̶;̶
̲r̲e̲t̲u̲r̲n̲ localforage.getItem(key)
.then (function(data) {
if (data) { // exists
if (has_expired(data.created_at)) {
̲r̲e̲t̲u̲r̲n̲ localforage.removeItem(key)
.then (function() {return cache_or_http(url,key);}) // <--HERE
.catch(function() {return do_error_handling();})
} else { // not expired
̶d̶.̶r̶e̶s̶o̶l̶v̶e̶(̶J̶S̶O̶N̶.̶p̶a̶r̶s̶e̶(̶d̶a̶t̶a̶.̶v̶a̶l̶u̶e̶)̶)̶;̶
return JSON.parse(data.value);
}
} else {
// doesn't exist
return $http.get(url)
.then (function(data) {
cache_entry = {
'value': JSON.stringify(data),
'created_at': moment().toString()
};
̲r̲e̲t̲u̲r̲n̲ localforage.setItem(key, cache_entry);
̶d̶.̶r̶e̶s̶o̶l̶v̶e̶(̶d̶a̶t̶a̶)̶;̶
̶r̶e̶t̶u̶r̶n̶ ̶(̶d̶.̶p̶r̶o̶m̶i̶s̶e̶)̶;̶
});
} // doesn't exist
}); // getItem .then
̶r̶e̶t̶u̶r̶n̶ ̶(̶d̶.̶p̶r̶o̶m̶i̶s̶e̶)̶;̶
}
Para mais informações, veja
- É um "Antipadrão diferido"?