AngularJS - misturando HTTP e promessas personalizadas com recursão

Oct 23 2020

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

1 georgeawg Oct 23 2020 at 08:38

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"?