Подтвердить что ты не робот

Кэширование объекта обещания в службе AngularJS

Я хочу реализовать динамическую загрузку статического ресурса в AngularJS с помощью Promises. Проблема: у меня есть пара компонентов на странице, которые могут (или нет, зависят от того, которые отображаются, таким образом динамические) должны получить статический ресурс с сервера. После загрузки он может быть кэширован для всего срока службы.

Я реализовал этот механизм, но я новичок в Angular и Promises, и я хочу убедиться, что это подходящее решение\подход.

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;
}

Итак, выполняется только один запрос, и все последующие вызовы loadDataPromise() возвращают первое обещание. Кажется, это работает для запроса, что в прогресс или тот, который уже закончился некоторое время назад.

Но это хорошее решение для кэширования Promises?

4b9b3361

Ответ 1

Это правильный подход?

Да. Использование memoisation для функций, которые возвращают promises общую технику, чтобы избежать повторного выполнения асинхронных (и обычно дорогостоящих) задач. Обещание упрощает кэширование, потому что не нужно различать текущие и готовые операции, они оба представлены как (то же) обещание для результата.

Это правильное решение?

Нет. Эта глобальная переменная data и разрешение с undefined не предназначены для работы promises. Вместо этого выполните обещание с результатом data! Это также упрощает кодирование:

var dataPromise = null;

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

Затем вместо loadDataPromise().then(function() { /* use global */ data }) это просто getData().then(function(data) { … }).

Чтобы еще больше улучшить шаблон, вы можете скрыть dataPromise в области закрытия и заметить, что вам понадобится поиск для другого promises, когда getData принимает параметр (например, url).

Ответ 2

Для этой задачи я создал службу, называемую defer-cache-service, которая удаляет весь этот код плиты котла. Он вписывается в Typescript, но вы можете захватить скомпилированный js файл. Github исходный код.

Пример:

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

и потребляйте

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

Важно отметить, что если пусть две или более части, вызывающие один и тот же loadDataPromise, и в то же время, вы должны добавить эту проверку

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

в противном случае вы будете делать повторяющиеся вызовы для бэкэнд.

Ответ 3

Этот шаблон проектирования будет кэшировать все, что возвращается при первом запуске, и возвращать кешированную вещь каждый раз, когда она снова вызывает.

const asyncTask = (cache => {
  return function(){
    // when called first time, put the promise in the "cache" variable
    if( !cache ){
        cache = new Promise(function(resolve, reject){
            setTimeout(() => {
                resolve('foo');
            }, 2000);
        });
    }
    return cache;
  }
})();

asyncTask().then(console.log);
asyncTask().then(console.log);