Предотвратить возврат предыдущего, но более длительного запроса $http после самого последнего запроса

Я только что столкнулся со странной ситуацией и не смог найти ответ после некоторых поисков.

У меня есть текстовое поле, которое я использую, чтобы позволить пользователю вводить ключевые слова для фильтрации данных таблицы. У меня есть директива ng-change для элемента ввода, который будет запускать этот код:

return $http.get(url).then(function (response) {
    return response.data;
});

Все это прекрасно работало, пока наш тестер не обнаружил нежелательное поведение в IE11. Вот пример ввода «M-A-T-T» в текстовое поле в IE10:

введите здесь описание изображения

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

Вот тот же пример ввода «M-A-T-T» в текстовое поле в IE11.

введите здесь описание изображения

Необъяснимым образом второй запрос занимает почти 2 секунды, что происходит после завершения четвертого и последнего запроса. Это приводит к тому, что результаты запроса «MA» отображаются, когда пользователь ожидает результатов запроса «MATT» (что в настоящее время находится в его текстовом поле).

Как это можно решить в Angular? Заранее спасибо.

ОБНОВЛЕНИЕ Основываясь на ответе Фрости, я реализовал следующее (в дополнение к подпрыгиванию), которое отлично работает:

var cancelDeferred;

var getUsers = function (criteria) {
    if (cancelDeferred) {
        cancelDeferred.resolve();
    }
    cancelDeferred = $q.defer();
    return $http.get(url, { timeout: cancelDeferred.promise }).then(function (response) {
        cancelDeferred = undefined;
        return response.data;
    });
};

На самом деле основной проблемой была обработка ошибок при вызове этого метода. Тайм-аут возвращает ошибку точно так же, как 500 возвращает ошибку. Я хочу игнорировать тайм-ауты и обрабатывать фактические ошибки. Вот мое решение для этого:

function onError(data, status) {
    if (data.data !== null && data.status !== 0) {
        //handle error
    }
}

Теперь я попытаюсь выяснить, есть ли способ реализовать это промис-тайминг глобально вместо того, чтобы изменять кучу вызовов $http.get()...


person im1dermike    schedule 29.10.2015    source источник
comment
Параметр debounce может быть полезен. Взгляните на второй ответ здесь: stackoverflow.com/questions/14722577/   -  person Anderson Pimentel    schedule 29.10.2015


Ответы (1)


В документации по $http говорится об объекте конфигурации, который вы можете передать в качестве второго аргумента вызову $http.get, например:

$http.get(url, config);

В этой конфигурации говорится о свойстве «тайм-аут», которое вы можете установить. Если вы установите это свойство как обещание, то, если вы разрешите обещание, оно прервет запрос. Ознакомьтесь с документацией для описания там.

Даже если вы используете debounce, вы захотите использовать этот «тайм-аут», чтобы прервать запрос.

https://docs.angularjs.org/api/ng/service/$http

Итак, вы бы сделали что-то вроде этого:

var cancelDeferred;
function makeRequest(){
    if(cancelDeferred) cancelDeferred.resolve(); //when this gets resolved, the previous request will abort. 
    cancelDeferred = $q.defer();
    return $http.get(url,{timeout:cancelDeferred.promise})
        .then(function(res){
            cancelDeferred = undefined;
            return res;
        });
}

Итак, вы передаете обещание запросу .get внутри объекта конфигурации в качестве свойства «тайм-аут». Если вы разрешите это отложено до того, как ответ вернется, это прервет запрос.

person frosty    schedule 29.10.2015
comment
Спасибо! Я понимаю, что делает bounce, но не могли бы вы немного подробнее объяснить, что делает этот тайм-аут в запросе $http? Кажется, я не могу полностью понять это из документации. - person im1dermike; 29.10.2015