Избегайте нескольких запросов ajax angularJS

Я пытаюсь избежать нескольких ajax-запросов к серверу на фабрике. Я уже добавил небольшую службу кэширования, но этого недостаточно для того, к чему я стремлюсь: эта фабрика может вызываться несколько раз, прежде чем сервер ответит, вызывая генерацию множественных запросов к серверу.

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

Это мой код:

myApp.factory('User', ['Restangular', '$q',
  function (Restangular, $q) {
    var userCache, alreadyRun = false;
    return {
      getUser: function () {
        var deferred = $q.defer(), firstRun= $q.defer();

        if (!userCache && !alreadyRun) {
          alreadyRun = true;

          Restangular.all('user').getList().then(function (user) {
            console.log('getting user live ');
            userCache = user[0].email;
            firstRun.resolve(user[0].email);
          });
        } else if (!userCache && alreadyRun) {
          console.log('waiting for the first promise to be resolved ');
          firstRun.then(function(user) {
            console.log('resolving the promise');
            deferred.resolve(userCache);
          });

        } else {
          console.log('resolving the promise from the cache');
          deferred.resolve(userCache)
        }
        return deferred.promise;
      }
    };
  }
]);

person Mimo    schedule 14.01.2014    source источник
comment
Я добавил свою окончательную реализацию в ответы.   -  person Mimo    schedule 13.03.2014


Ответы (3)


Вы можете просто вернуть исходное обещание, если запрос уже был сделан. Что-то вроде этого должно работать;

myApp.factory('User', ['Restangular', '$q',
  function (Restangular, $q) {
    var deferred = false;

    return {
      getUser: function () {

        if(deferred) {
          return deferred.promise;
        }

        deferred = $q.defer();

        Restangular.all('user').getList().then(function (user) {
          deferred.resolve(user[0].email);
        });

        return deferred.promise;
      }
    };
  }
]);

Также ознакомьтесь с документацией Restangular по кэшированию запросов.

person smilly92    schedule 09.03.2014
comment
Спасибо, что поделились @smilledge. Тем временем, когда я задал вопрос, я кое-что реализовал сам. Однако ваше решение выглядит очень чистым и компактным, поэтому я принял ваш ответ. Взгляните на мой и дайте мне знать, что вы думаете о нем :) - person Mimo; 13.03.2014

Каждый раз, когда вы запускаете getUser, для firstRun создается новая отсрочка. Если он уже запущен, вы вызываете firstRun.then, но это обещание никогда не разрешается.

person Jonathan Rowny    schedule 14.01.2014
comment
Но есть ли способ добиться того, что я пытаюсь сделать? - person Mimo; 15.01.2014
comment
Не могу сказать вам без дополнительного контекста. GetUser вызывается сразу из нескольких мест? Вы можете использовать Resolve на маршруте, чтобы убедиться, что он загружен, прежде чем вы начнете что-то делать. - person Jonathan Rowny; 15.01.2014
comment
Привет, @JonathanRowny. Я добавил ответ со своей реализацией, посмотри и дай мне знать, что ты думаешь. Я принял в качестве ответа ответ от smilledge, потому что он выглядит очень чистым. - person Mimo; 13.03.2014

Спасибо всем за ответы, тем временем я нашел способ кэшировать эту конкретную фабрику:

.factory('User', ['Restangular', '$q',
  function (Restangular, $q) {
    var userCache, promises = [];
    return {

      getUser: function () {

        var deferred = $q.defer();

        if (promises.length > 0) {

          promises.push(deferred);

        } else if (!userCache) {

          promises.push(deferred);

          Restangular.all('user').getList().then(function (user) {
            var i;
            userCache = user[0];
            for (i = promises.length; i--;) {
              promises.shift().resolve(userCache);
            }
          });

        } else {

          deferred.resolve(userCache);

        }

        return deferred.promise;

      }
    };
  }
]);

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

Я описал реализацию этого кэширования промисов здесь.

person Mimo    schedule 12.03.2014