【问题标题】:jQuery ajax beforeSendjQuery ajax beforeSend
【发布时间】:2013-04-09 09:49:42
【问题描述】:

我有一个简单的 AJAX 调用,它在 beforeSend 和 complete 上执行一个函数。他们执行得很好,但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();
            }
        });

【问题讨论】:

  • 旁注:async=false 的任何原因?
  • 更新页面常用UI。我不希望用户在执行时能够使用这些操作。
  • beforeSend 与async:false 结合使用没有任何意义。如果你想保留async:false,你可以在ajax(...)之前添加blockUI调用,因为无论如何代码都会同步执行。
  • 我删除了 beforeSend 并将 blockUI 放在请求之前,但是功能没有改变。
  • “功能没有改变”是什么意思?你是说blockUI 调用在success 处理程序之后仍在执行吗?

标签: javascript jquery jquery-blockui


【解决方案1】:

您的问题是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 success 和 complete 回调被执行

这里有一些 jsFiddle 例子来演示这个问题:

Example 1:这就是你遇到的情况。 blockUI 文本直到 ajax 调用执行后才会显示。

Example 2:这与您的情况完全相同,但在ajax 调用之前有一个alert。因为存在alert,所以blockUI 内的超时将blockUI 文本的外观置于alert 之后而不是ajax 之后。

Example 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();
                }
         });
    

    【讨论】:

    • 我同意你的推理......我想补充一点,从技术上讲,你甚至不需要complete 回调。您可以在ajax() 部分之后添加$.unblockUI(),因为它无论如何都是异步的。
    • 我删除了 beforeSend 并完成并在 .ajax 请求之前和之后放置了逻辑,但是功能没有改变
    【解决方案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);
      };
      

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

      【讨论】:

        猜你喜欢
        • 2017-10-21
        • 1970-01-01
        • 2013-03-28
        • 1970-01-01
        • 1970-01-01
        • 2013-12-25
        • 2015-07-19
        • 2011-07-09
        • 2014-08-01
        相关资源
        最近更新 更多