Автозаполнение пользовательского интерфейса jQuery: отмена запроса

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

Итак, вот что у меня есть:

$('#myselector').autocomplete({
    source: function(request, response) {
        var data = {};
        if($(this).data('xhr')) {
            console.log('aborting...');
            $(this).data('xhr').abort();
        }
        // *snip* add some stuff to data
        $(this).data('xhr', $.ajax({
            url: '/ajax/major_city',
            dataType: 'json',
            data: data,
            success: function(data, textStatus, $xhr) {
                response(data);
            },
            complete: function($xhr, textStatus) {
                console.log(textStatus);
                if(textStatus === 'abort') {
                    console.log('aborted!');
                    response([]);
                }
            }
        }));
    },
// ....

Таким образом, всякий раз, когда запускается обратный вызов «источник», он проверяет, существует ли элемент XHR для этого ввода (будет неопределенным в первый раз), и если да, прерывает его (побочный вопрос: как я могу проверить, завершен ли запрос?Нет смысла пытаться прервать запросы, которые уже завершены).

Но документы говорят:

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

Итак, в нижней части моего кода вы увидите, что я (пытаюсь) проверить, был ли запрос прерван, и если да, я возвращаю пустой список. Но это "прервано!" log никогда не вызывается. Он всегда говорит «успех», даже если он прерывается. Почему это?


Изменить: только что попытался вывести $(this).data('xhr').readyState. Кажется, никогда не бывает меньше 4, что говорит мне о том, что source не вызывается снова, пока последний запрос не вернет ответ. А жаль, потому что мы могли бы прервать запросы раньше и немного ускорить время отклика...


person mpen    schedule 24.06.2011    source источник


Ответы (2)


bdparrish имеет правильную идею

Увеличьте время ожидания плагина перед отправкой запроса:

$( ".selector" ).autocomplete({ delay: 500 }); //default is 300

Таким образом, вы отправите запрос только после того, как подозреваете, что пользователь закончил печатать. Лучше делать меньше http-запросов, чем делать много и отменять их.

-Ледедже

person lededje    schedule 17.10.2012
comment
Это не реальное решение IMO. Это может помочь смягчить проблему, но независимо от того, какую задержку вы установите, они могут нажать другую клавишу через мс. Кроме того, вы жертвуете временем отклика, чтобы уменьшить количество запросов. Я могу печатать со скоростью около 100 слов в минуту, что, я думаю, примерно соответствует 1 символу каждые 150 мс, поэтому я хотел бы установить задержку лишь немного выше. Наконец, независимо от законности этого ответа, вы не решаете проблему, почему прерывание не запускает обратный вызов. - person mpen; 18.10.2012
comment
Если вы правильно внедрили плагин, все запросы будут перехвачены в полной функции. Затем вы можете прервать выполнение кода при нажатии другой клавиши. Код состояния не будет прерван, потому что вы не сообщили серверу, что делаете это. Если вы хотите, чтобы это работало так, поймайте успешный возврат запроса и затем ничего с ним не делайте. - person lededje; 18.10.2012

Есть ли причина, по которой вы не можете установить временной интервал ожидания, пока пользователь «кажется», что он закончил печатать? Параметр «задержка» устанавливает миллисекунды, в течение которых он будет ждать после ввода последней буквы перед поиском.

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

person bdparrish    schedule 24.06.2011
comment
Я не совсем уверен, что вы пытаетесь сказать своим первым абзацем. Я хочу уменьшить задержку и отменить старые запросы, чтобы улучшить время отклика. Если пользователь печатает слишком медленно (превышая задержку), он может запустить запрос ajax непосредственно перед тем, как он нажмет следующую букву. Этот запрос больше недействителен, поэтому его следует немедленно прервать, чтобы нам не пришлось ждать завершения этого запроса, прежде чем начинать следующий. - person mpen; 24.06.2011
comment
Нет, я не возвращаю «отмена». В документах конкретно указано, что textStatus может быть одним из следующих: Success, notmodified, error, timeout, abort или parsererror. Я предполагаю, что получу текстовый статус прерывания, когда прерву запрос, так что это то, что я слушал. Но, учитывая, что у меня никогда не было возможности прервать, потому что следующее событие даже не запускается до тех пор, пока предыдущее успешно не вернется, этот вопрос спорный. - person mpen; 24.06.2011