Almacenamiento en caché de un objeto de promesa en el servicio AngularJS

Resuelto andrew.fox asked hace 11 años • 3 respuestas

Quiero implementar una carga dinámica de un recurso estático en AngularJS usando Promises. El problema: tengo un par de componentes en la página que podrían (o no, depende de cuáles se muestren, por lo tanto dinámicos) necesitar obtener un recurso estático del servidor. Una vez cargado, se puede almacenar en caché durante toda la vida útil de la aplicación.

He implementado este mecanismo, pero soy nuevo en Angular y Promises, y quiero asegurarme de si esta es una solución/enfoque correcto.

var data = null;
var deferredLoadData = null;

function loadDataPromise() {
  if (deferredLoadData !== null)
    return deferredLoadData.promise;

  deferredLoadData = $q.defer();

  $http.get("data.json").then(function (res) {
    data = res.data;
    return deferredLoadData.resolve();
  }, function (res) {
    return deferredLoadData.reject();
  });

  return deferredLoadData.promise;
}

Por lo tanto, solo se realiza una solicitud y todas las siguientes llamadas a loadDataPromise() recuperan la primera promesa hecha. Parece funcionar para una solicitud que está en progreso o una que ya terminó hace algún tiempo.

¿Pero es una buena solución para almacenar en caché las promesas?

andrew.fox avatar Sep 11 '13 22:09 andrew.fox
Aceptado

¿Es este el enfoque correcto?

Sí. El uso de la memorización de funciones que regresan promete una técnica común para evitar la ejecución repetida de tareas asincrónicas (y generalmente costosas). La promesa facilita el almacenamiento en caché porque no es necesario distinguir entre operaciones en curso y finalizadas; ambas se representan como (la misma) promesa para el valor del resultado.

¿Es esta la solución correcta?

No. Esa variable global datay la resolución undefinedno es la forma en que se pretende que funcionen las promesas. En lugar de eso, ¡cumple la promesa con el resultado data! También facilita mucho la codificación:

var dataPromise = null;

function getData() {
    if (dataPromise == null)
        dataPromise = $http.get("data.json").then(function (res) {
           return res.data;
        });
    return dataPromise;
}

Entonces, en lugar de loadDataPromise().then(function() { /* use global */ data })eso, es simplemente getData().then(function(data) { … }).

Para mejorar aún más el patrón, es posible que desee ocultarlo dataPromiseen un alcance de cierre y observar que necesitará una búsqueda de diferentes promesas cuando getDatatome un parámetro (como la URL).

Bergi avatar Sep 11 '2013 15:09 Bergi

Para esta tarea creé un servicio llamado defer-cache-service que elimina todo este código de placa de caldera. Está escrito en Typecript, pero puede obtener un archivo js compilado. Código fuente de Github .

Ejemplo:

function loadCached() {
   return deferCacheService.getDeferred('cacke.key1', function () {
      return $http.get("data.json");
   }); 
} 

y consumir

loadCached().then(function(data) {
//...
});

Una cosa importante a tener en cuenta es que si digamos que dos o más partes llaman al mismo loadDataPromise y al mismo tiempo, debes agregar esta verificación

if (defer && defer.promise.$$state.status === 0) {
   return defer.promise;
}

de lo contrario, realizará llamadas duplicadas al backend.

Andzej Maciusovic avatar Nov 30 '2015 14:11 Andzej Maciusovic