Задержка службы 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);
Ответы
Ответ 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);
});
Надеюсь, это поможет кому-то!