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

Jquery ajax beforesend

У меня есть простой вызов ajax, который выполняет функцию на beforeSend и при завершении. Они выполняются отлично, но beforeSend "кажется" не выполняется до тех пор, пока не будет успешным. При отправке отправляется уведомление "Подождите". Если я положу разрыв после функции в beforeSend, он покажет это уведомление, а затем ударит успех. Без точки останова он будет сидеть и думать, ожидая ответа, а затем, пожалуйста, подождите, пока уведомление не появится на долю секунды после успеха. Желаемая функциональность заключается в том, чтобы получить уведомление, как только запрос будет отправлен, чтобы он отображался, пока он ожидает ответа.

        $.ajax({
            type : 'POST',
            url : url,
            async : false,
            data : postData,
            beforeSend : function (){
                $.blockUI({
                    fadeIn : 0,
                    fadeOut : 0,
                    showOverlay : false
                });
            },
            success : function (returnData) {
                //stuff
            },
            error : function (xhr, textStatus, errorThrown) {
                //other stuff
            },
            complete : function (){
                $.unblockUI();
            }
        });
4b9b3361

Ответ 1

Ваша проблема - флаг async:false. Помимо того факта, что это плохая практика (и действительно имеет смысл только в очень ограниченном числе случаев), она фактически противоречит порядку выполнения остальной части кода. Вот почему:

Кажется, что где-то в коде blockUI они устанавливают setTimeout. В результате код blockUI ждет очень короткий промежуток времени. Поскольку следующая команда в очереди - это вызов ajax(), выполнение этого заклада blockUI устанавливается прямо за ним. И поскольку вы используете async:false, он должен дождаться завершения полного вызова ajax до его запуска.

В деталях, вот что происходит:

  • Вы вызываете blockUI
  • blockUI имеет setTimeout и запускается после истечения таймаута (даже если длина таймаута равна 0, первая строка будет ajax())
  • ajax() вызывается с async:false, что означает, что JS останавливает все, пока запрос не вернет
  • ajax() возвращается успешно, и выполнение JS может продолжаться
  • код setTimeout внутри blockUI, вероятно, закончился, поэтому он будет выполнен следующим образом
  • он выглядит как blockUI работает как часть success, но на самом деле он только что оказался в очереди из-за тайм-аута

Если вы НЕ используете async:false, выполнение будет выполняться следующим образом:

  • Вы вызываете blockUI
  • blockUI имеет setTimeout и запускается после истечения таймаута (даже если длина таймаута равна 0, первая строка будет ajax())
  • ajax() вызывается и отправляет запрос на сервер.
  • Пока он подключается к серверу, обычное выполнение JS продолжается
  • код setTimeout внутри blockUI, вероятно, закончился, поэтому он будет выполнен следующим образом
  • отображается текст blockUI
  • если там больше JS-кода, выполнение JS выполняется до тех пор, пока не будут выполнены обратные вызовы AJAX success и complete

Вот некоторые примеры jsFiddle для демонстрации проблемы:

Пример 1: Это та ситуация, с которой вы столкнулись. Текст blockUI не отображается до тех пор, пока не будет выполнен вызов ajax.

Пример 2: это та же самая ситуация, что и у вас, но с alert перед вызовом ajax. Поскольку существует alert, таймаут внутри blockUI помещает внешний вид текста blockUI после alert, а не после ajax.

Пример 3: так предполагается, что он будет работать без async:false

Ответ 2

Это, скорее всего, из-за async : false. Поскольку ваш вызов синхронный, после того, как начнется ваш вызов функции $.ajax(), ничего не произойдет до тех пор, пока не будет получен ответ, а следующая вещь, касающаяся вашего кода, будет обработчиком success

Чтобы он работал, вы можете сделать что-то вроде этого

$.blockUI({
        fadeIn : 0,
        fadeOut : 0,
        showOverlay : false
});
// and here goes your synchronous ajax call
$.ajax({
            type : 'POST',
            url : url,
            async : false,
            data : postData,
            success : function (returnData) {
                //stuff
            },
            error : function (xhr, textStatus, errorThrown) {
                //other stuff
            },
            complete : function (){
                $.unblockUI();
            }
     });

Ответ 3

$.blockUI({
        fadeIn : 0,
        fadeOut : 0,
        showOverlay : false
});
setTimeout(function() {
     $.ajax({
            type : 'POST',
            url : url,
            async : false,
            data : postData,
            success : function (returnData) {
                //stuff
            },
            error : function (xhr, textStatus, errorThrown) {
                //other stuff
            }
     });
},100);
$.unblockUI();

http://bugs.jquery.com/ticket/7464

Ответ 4

Другим подходом может быть функция перегрузки $.ajax

$.orig_ajax = $.ajax;

$.ajax = function() {
    var settings = {async: true};
    if (2 == arguments.length && 'string' == typeof arguments[0] && 'object' == typeof arguments[1])
        settings = arguments[1];
    else if (arguments.length && 'object' == typeof arguments[0])
        settings = arguments[0];

    if (!settings.async && 'function' == typeof settings.beforeSend) {
        var args = arguments;

        settings.beforeSend();
        var dfd = $.Deferred();
        setTimeout(function() {
            $.orig_ajax.apply($, args).then(dfd.resolve)
                                      .fail(dfd.reject);
        } ,100);
        return dfd.promise();
    } else
        return $.orig_ajax.apply($, arguments);
};

не совершенен (из-за другого отложенного объекта), но может быть полезным.