【问题标题】:jQuery how to make the ajax request "synchronous" when async is truejQuery如何在异步为真时使ajax请求“同步”
【发布时间】:2012-03-14 07:56:05
【问题描述】:
var tds = ["0", "1", "2", "3", "4", "5", "6"];

for (var i = 0; i < tds.length; i++) {

    jQuery("#notification-bar").html('I am doing ' + tds[i]);

    jQuery.ajax({
        url: "/ajax_json_echo/",
        type: "POST",
        timeout: 10000,
        data: tds[i],
        success: function(response) {
       
        },
        error: function(x, t, m) {
        
 
        }
    });


} //end for

jQuery("#notification-bar").html("Done!");​

/ajax_json_echo/ 处理 tds 可能需要 10 秒甚至更长时间。

通知栏的预期结果是

我在做 0

我正在做 1

我在做 2

...

完成!

我得到的实际结果是:

完成!

我猜是 jquery ajax 的 async 变量设置为 true 造成的。

如果设置为 false,浏览器将被冻结。当它恢复时,我得到“完成!”仅限。

【问题讨论】:

    标签: php jquery progress-bar


    【解决方案1】:

    浏览器运行 JavaScript 并在同一个线程上进行页面渲染,因此当 JS 运行时不会发生重绘。这意味着您的整个 for 循环将完成,状态消息将设置为“完成!” 页面更新之前。

    在 async 为真的情况下,所有 Ajax 请求最初都会排队,并且消息设置为“完成!”然后稍后异步处理响应。在异步设置为 false 的情况下,Ajax 请求一次完成一个,在响应到来之前没有进一步的操作。无论哪种方式,浏览器都没有机会显示“我正在做...”消息。

    您可以从 Ajax 完成(或成功)回调中触发每个后续调用,而不是使用循环:

    var tds = ["0", "1", "2", "3", "4", "5", "6"];
    
    function doNextAjax(i) {
       if (i < tds.length) {
          jQuery("#notification-bar").html('I am doing ' + tds[i]);
    
          jQuery.ajax({
             url: "/ajax_json_echo/",
             type: "POST",
             timeout: 10000,
             data: tds[i],
             success: function(response) {
    
             },
             error: function(x, t, m) {    
    
             },
             complete: function() {
                doNextAjax(i + 1);
             }
          });
       } else {
          jQuery("#notification-bar").html("Done!");​
       }
    }
    
    doNextAjax(0);
    

    每次调用doNextAjax() 时,它都会更新状态消息并发出一个Ajax 请求,仅此而已。当函数退出浏览器时,就有机会重新渲染并实际显示该消息。然后,当触发完成回调时,它会再次为下一项调用该函数。当没有剩余物品时,它会设置“完成!”消息。

    请注意,使用完整的回调来触发下一个 Ajax 调用意味着即使特定请求失败,它也会继续进行。如果您想停止出错,您可以摆脱完整的处理程序并将doNextAjax(i+1) 移动到成功回调中。

    【讨论】:

    • 谢谢。这就是我要的。 :]
    【解决方案2】:

    通常这是您使用ajax()success 回调参数来在AJAX 请求完成时运行函数。

    http://api.jquery.com/jQuery.ajax/

    【讨论】:

      【解决方案3】:

      如果您可以使用 HTML5 元素,请使用 &lt;progress&gt; 元素,这就是他存在的原因。
      在每个ajax请求的成功回调中增加progress-bar值。

      var progress = document.getElementById('progress');
      progress.max = tds.length;  
      
      ...
      success: function(){
                             progress.value++;
                         }
      

      LIVE DEMO

      【讨论】:

      • 感谢您的回答。我正在使用 jquery ui,它确实具有进度条功能。实际上,我把 jQuery( "#progress" ).progressbar( ( i / ( tds.length - 1 ) ) * 100 );在成功回调中
      • “我在做”通知对我来说更重要。
      • @user752492。我只是不明白你面临的问题是什么。尝试用fiddle向我展示
      【解决方案4】:

      这里是解决方案,你应该看看 jQuery defered object

      $.when($.ajax("/page1.php"), $.ajax("/page2.php")).done(function(a1,  a2){
          /* a1 and a2 are arguments resolved for the 
              page1 and page2 ajax requests, respectively */
         var jqXHR = a1[2]; /* arguments are [ "success", statusText, jqXHR ] */
         if ( /Whip It/.test(jqXHR.responseText) ) {
            alert("First page has 'Whip It' somewhere.");
         }
      });
      

      http://api.jquery.com/jQuery.when/

      【讨论】:

        【解决方案5】:

        你写的回复会发生。改变

        jQuery("#notification-bar").html('I am doing ' + tds[i]);
        jQuery("#notification-bar").html("Done!");​
        

        jQuery("#notification-bar").append('I am doing ' + tds[i]);
        jQuery("#notification-bar").append("Done!");​
        

        你会看到结果。但是,行为不是你所期望的。 For 循环将一个接一个地启动所有 AJAX 调用。如果您只想在最后一个 AJAX 调用完成后启动下一个 AJAX 调用,您应该使用 jQuery Deferred 对象来管理它。

        我在这里总结了一个例子http://jsfiddle.net/DXYZw/2/

        var tds = ["0", "1", "2", "3", "4", "5", "6"];
        
        var sendRequest = function(ary, data) {
            if (!ary.length) {
                // no more calls to be made
                jQuery("#notification-bar").append("Done!");
                return;
            }
            jQuery("#notification-bar").append('I am doing ' + tds.length);
            dfAJAX(ary)
                .done(sendRequest)
                .fail(function() {
                    alert("error");
                });
        }
        
        var dfAJAX = function(ary) {
            var dfd = new jQuery.Deferred();
        
            var dataToSend = ary.pop();
        
            jQuery.ajax({
                url: "/ajax_json_echo/",
                type: "POST",
                timeout: 10000,
                data: dataToSend
            })
                .done(function(data) {
                    dfd.resolve(ary, data);
                })
                .fail(function() {
                    dfd.reject();
                })
        
            return dfd.promise();
        }
        
        sendRequest(tds);
        

        【讨论】:

        • 好的,这是另一种解决方案。很酷的一个。谢谢。我来看看延迟对象。
        猜你喜欢
        • 2012-12-07
        • 2023-04-01
        • 2016-10-22
        • 2016-02-13
        • 1970-01-01
        • 2013-03-09
        • 1970-01-01
        相关资源
        最近更新 更多