Метод POST, сообщение об ошибке состояния (отменено)

У меня есть следующий код, который дает мне сообщение об ошибке Method POST, Status (canceled):

$(document).ready(function() {
    var xhr = false;

    get_default();

    $('#txt1').keyup( function() {
        if(xhr && xhr.readyState != 4){
            alert("abort");
            xhr.abort();
        }

        if ($("#txt1").val().length >= 2) {
            get_data( $("#txt1").val() );
        } else {
            get_default();
        }
    });

    function get_data( phrase ) {
        xhr = $.ajax({
            type: 'POST',
            url: 'http://intranet/webservices.asmx/GetData',
            data: '{phrase: "' + phrase + '"}',
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            success: function( results ) {
                $("#div1").empty();

                if( results.d[0] ) {
                    $.each( results.d, function( index, result ) {
                        $("#div1").append( result.Col1 + ' ' + result.Col2 + '<br />' );
                    });
                } else {
                    alert( "no data available message goes here" );
                }
            },
            error: function(xhr, status, error) {
                 var err = eval("(" + xhr.responseText + ")");
                 alert(err.Message) ;
            }
        });
    }

    function get_default() {
        $('#div1').empty().append("default content goes here.");
    }

});

Код действительно работает до тех пор, пока каждый запрос ajax завершается, но если я быстро введу в txt1, т.е. введите следующий символ до завершения предыдущего запроса, я получаю сообщение об ошибке Method POST, Status (canceled).

Кто-нибудь знает, почему это происходит и как исправить ошибку?

Ответы

Ответ 1

Я полагаю, что проблема очень проста. Если вы вызываете xhr.abort();, то error обратный вызов $.ajax будет называться для ожидающего запроса. Поэтому вы должны просто игнорировать такой случай внутри обратного вызова error. Поэтому обработчик error может быть изменен на

error: function(jqXHR, textStatus, errorThrown) {
    var err;
    if (textStatus !== "abort" && errorThrown !== "abort") {
        try {
            err = $.parseJSON(jqXHR.responseText);
            alert(err.Message);
        } catch(e) {
            alert("ERROR:\n" + jqXHR.responseText);
        }
    }
    // aborted requests should be just ignored and no error message be displayed
}

P.S. Вероятно, для вас может быть интересен еще один мой старый ответ по проблеме закрытия.

Ответ 2

Это потому, что вы вызываете метод abort, который, возможно, запускает обработчик ошибок с соответствующим сообщением об ошибке.

Возможно, вы дождитесь завершения предыдущего запроса ajax до следующего вызова.

Ответ 3

Вы используете событие keyup, которое кажется проблемой.

Если что-нибудь вообще, вам нужно подождать после ввода одного символа, прежде чем предпринимать действия.

Лучшим решением может быть стратегия, аналогичная JQuery AutoComplete COmponent.

Ответ 4

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

Ситуация 1:

The user types slow enough (lets say about one key every 200+ miliseconds

Ситуация 2:

The user types fast (my average is about 20 to 50 miliseconds per key)

В следующем примере нет необходимости прерывать или игнорировать вызовы Ajax, вы не рассылаете спам Ajax-вызовы и используете объект для обработки своей работы. (Я даже jsFiddled для вас)

var Handler = {

    /**
     * Time in ms from the last event
     */
    lastEvent: 0,

    /**
     * The last keystroke must be at least this amount of ms ago
     * to allow our ajax call to run
     */
    cooldownPeriod: 200,

    /**
     * This is our timer
     */
    timer: null,

    /**
     * This should run when the keyup event is triggered
     */
    up: function( event )
    {
        var d = new Date(),
            now = d.getTime();

        if( ( now - Handler.lastEvent ) < Handler.cooldownPeriod ) {
           // We do not want to run the Ajax call
            // We (re)set our timer
            Handler.setTimer();
        } else {
            // We do not care about our timer and just do the Ajax call
            Handler.resetTimer();
            Handler.ajaxCall();
        }

        Handler.lastEvent = now;
    },

    /**
     * Function for setting our timer
     */
    setTimer: function()
    {
        this.resetTimer();
        this.timer = setTimeout( function(){ Handler.ajaxCall() }, this.cooldownPeriod );
    },

    /**
     * Function for resetting our timer
     */
    resetTimer: function()
    {
        clearTimeout( this.timer );
    },

    /**
     * The ajax call
     */
    ajaxCall: function()
    {
        // do ajax call
    }

};

jQuery( function(){

    var field = jQuery( '#field' );

    field.on( 'keyup', Handler.up );

});

Надеюсь, что это поможет.

Ответ 5

Ajax является асинхронным типом, его не рекомендует, чтобы u отправлял запрос на каждое событие keyup, попробуйте...

async: false

в методе post... он приостанавливает последующие сообщения до тех пор, пока текущий запрос не выполнит обратный вызов

Ответ 6

Реально, вам нужен метод setTimeout, чтобы не запускать избыточные вызовы ajax.

clearTimeout(timer);

if($("#txt1").val().length >= 2){
    timer = setTimeout(function(){
        get_data($("#txt1").val());
    }, 400);
}else{
    get_default();
}

Это должно устранить вашу проблему.