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

Задержка службы angular.js $http

У меня есть несколько фабрик angular для создания ajax-вызовов для унаследованных веб-сервисов ASP.NET.asmx, например:

module.factory('productService', ["$http",
function ($http) {
    return {
        getSpecialProducts: function (data) {
            return $http.post('/ajax/Products.asmx/GetSpecialProducs', data);
        }
    }
} ]);

Я тестирую локальную сеть, поэтому время ответа "слишком" хорошо. Есть ли разумный способ отсрочить $http через пару секунд от вызова для имитации плохого соединения?

Или мне нужно обернуть все вызовы методам factory в $timeout?

$timeout(function() {
  productService.getSpecialProducs(data).success(success).error(error);
}, $scope.MOCK_ajaxDelay);
4b9b3361

Ответ 1

Интересный вопрос!

Как вы уже упоминали, $timeout является наиболее логичным выбором для отложенного вызова. Вместо того, чтобы повсюду иметь вызовы $timeout, вы можете нажать ответный перехватчик, который обертывает обещание $http в обещании $timeout, как это концептуально описано в документации $http и зарегистрируйте его в одном из ваших блоков конфигурации. Это означает, что все вызовы $http зависят от задержки $timeout. Что-то вроде:

$httpProvider.interceptors.push(function($timeout) {
    return {
        "response": function (response) {
            return $timeout(function() {
                return response;
            }, 2500);
        }
    };
});

В качестве бонуса к вашему "симулировать плохую связь?", вы можете отклонить или сделать абсолютно ничего случайным образом. Хе-хе-хе.

Ответ 2

Новый эмулятор хром-устройства имеет функцию дросселирования сети:

enter image description here

Чтобы попасть туда: в Google Chrome нажмите F12, чтобы открыть Инструменты разработчика. Затем в левом верхнем углу щелкните значок "Режим режима переключения" (влево в меню "Элементы" ).

Ответ 3

Более подробная информация о ответе @stevuu

responseInterceptors, кажется, отменен (начиная с 1.2.20). Я изменил код для работы с механизмом interceptors:

$httpProvider.interceptors.push(function($q, $timeout) {
    return {
        'response': function(response) {
            var defer = $q.defer();
            $timeout(function() {
                        defer.resolve(response);
                }, 2300);
            return defer.promise;
        }
    };
});

Ответ 4

Вы можете использовать службу $q для defer(). pattern:

function someFunction(MOCK_ajaxDelay) {
   var deferred = $q.defer();
   $http.post('/ajax/Products.asmx/GetSpecialProducs', data).success(function(response) {
      $timeout(function() {deferred.resolve({ success: true, response: response })}, MOCK_ajaxDelay);  
   }).error(function() {
      $timeout(function() {deferred.resolve({ success: true, response: response } }, MOCK_ajaxDelay);  
   });
   return deferred.promise;
}

someService.someFunction(500).then(function(data) {
    if (data.success) {
      $scope.items = data.response.d;
    }
});

Но если вы на самом деле макет тестирования, лучшим решением является просмотр ngMock: http://docs.angularjs.org/api/ngMock. $httpBackend

Ответ 5

В то время как ответ @stevuu верен, с тех пор синтаксис изменился в новых версиях AngularJS. Обновленный синтаксис:

$httpProvider.interceptors.push(["$q", "$timeout", function ($q, $timeout) {
  function slower(response) {
    var deferred = $q.defer();
    $timeout(function() {
        deferred.resolve(response);
    }, 2000);
    return deferred.promise;
  }
  return {
    'response': slower
  };
}]);

Ответ 6

Вы можете достичь этого, используя обещание api в сочетании с $timeout. Функция $http.post возвращает обещание, из которого вы можете вызвать .success и .error(это специальные методы http). Это обещание разрешается, когда HTTP-запрос завершен. Если вы создадите свое собственное обещание, вы можете сказать ему, чтобы он задерживал 2 секунды, а затем разрешал, когда HTTP-запрос завершен:

module.factory('productService', function ($http, $q, $timeout) {

    return {
        getSpecialProducts: function (data) {
            var defer = $q.defer();
            $http.post('/ajax/Products.asmx/GetSpecialProducs', data).success(
              function(data) {
                // successful http request, resolve after two seconds
                $timeout(function() {
                    defer.resolve(data);
                }, 2000)
            }).error(function() {
                defer.reject("Http Error");
            })
            return defer.promise;
        }
    }

});

Но обратите внимание - вам нужно будет использовать функциональность promise.then(successCallback, errorCallback), то есть вы потеряете возможность доступа к заголовкам, статусу и конфигурации http из ваших контроллеров/директив, если вы явно не передадите их объекту, переданному в defer.resolve({})

Ссылки:

Ответ 7

В ответ на тестовый аспект вашего вопроса Fiddler имеет действительно полезную функцию, которая помогает, когда вам нужно моделировать задержки:

  • Перейдите на вкладку Автоответчики в Fiddler.
  • Добавьте правило с регулярным выражением, которое соответствует URL-адресу запроса, который вы хотите отложить.
  • Установите "ответить" на "* delay: 1000", где число - это задержка в миллисекундах.

Функциональность AutoResponder в Fiddler чрезвычайно полезна для тестирования JS, которая включает в себя множество HTTP-запросов. Вы можете настроить его для ответа с конкретными кодами ошибок HTTP, блочными ответами и т.д.

Ответ 8

Если вы используете службу, которая возвращает обещание, то внутри вы должны поместить return до $timeout, потому что это возвращает еще одно обещание.

return dataService.loadSavedItem({
    save_id: item.save_id,
    context: item.context
}).then(function (data) {
    // timeout returns a promise
    return $timeout(function () {
        return data;
    },2000);
});

Надеюсь, это поможет кому-то!