jQuery ajax beforeSend

28

我有一个简单的AJAX调用,在beforeSendcomplete上执行一个函数。它们被成功执行,但是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();
            }
        });

1
顺便提一下:为什么要使用 async=false - Dom
它正在更新页面上常用的用户界面。我不希望在执行此过程时用户能够使用这些操作。 - user1134179
2
beforeSend在与async:false组合使用时没有任何意义。如果您想保持async:false,您可以在ajax(...)之前添加blockUI调用,因为代码将以同步方式执行。 - Steve
我已经移除了beforeSend并将blockUI放在请求之前,但功能没有改变。 - user1134179
“the functionality hasn't changed”是什么意思?你是说blockUI调用仍然在success处理程序之后被执行吗? - Steve
它与我上面描述的方式没有改变。它在成功处理程序之前被调用。然而,直到它到达成功函数时才显示blockUI。 - user1134179
4个回答

28
您的问题在于async:false标志。除了事实上这是一种不好的做法(并且只有在非常有限的情况下才有意义),它实际上会干扰其余代码的执行顺序。原因如下:
看起来在 blockUI 代码中的某个地方他们设置了一个setTimeout。结果,blockUI 代码等待了很短的时间。由于队列中的下一个指令是ajax()调用,所以blockUI执行被放在紧随其后。并且,由于您使用的是async:false,必须等到完整的ajax调用完成后才能运行。
详细来说,以下是发生的情况:
- 您调用blockUI - 在超时完成后会执行blockUI其中设置了setTimeout(即使超时长度为0,下一行ajax()也将首先运行) - 调用 ajax() 并使用 async:false,这意味着JS停止一切直到请求返回 - ajax()成功返回,并允许JS执行继续 - 在 blockUI 代码内的 setTimeout 可能已经完成,因此它将在下一个执行 - 看起来blockUI会作为success的一部分运行,但实际上,由于超时的原因,它只是被排队了。
如果您不使用async:false,则执行顺序如下:
- 您调用blockUI - 在超时完成后会执行blockUI其中设置了setTimeout(即使超时长度为0,下一行ajax()也将首先运行) - 调用 ajax() 并向服务器发送请求。
  • 当它连接到服务器时,正常的JS执行会继续
  • blockUI代码中的setTimeout可能已经结束,所以接下来会执行它
  • blockUI文本出现
  • 除非还有其他JS代码,否则JS执行完成直到AJAX的successcomplete回调被执行
  • 这里有一些jsFiddle示例来演示这个问题:

    示例1:您遇到的情况。 blockUI文本直到ajax调用执行后才显示。

    示例2:与您的情况完全相同,但在ajax调用之前有一个alert。因为有一个alert,所以blockUI中的超时将blockUI文本的出现放在alert之后,而不是在ajax之后。

    示例3:这是没有使用async: false应该如何工作的方式。


    6
    这很可能是由于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();
                }
         });
    

    我同意你的推理...并且我想要补充一点,从技术上讲,你甚至不需要complete回调函数。你可以在ajax()部分之后直接添加$.unblockUI(),因为它本来就是异步的。 - Steve
    2
    我删除了 beforeSend 和 complete 并将逻辑放在 .ajax 请求之前和之后,但功能没有改变。 - user1134179

    0

    另一种方法可能是重载 $.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);
    };
    

    不是完美的(因为有不同的延迟对象),但可能会有所帮助。


    0
    $.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


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接