jQuery如何在异步为真时使ajax请求“同步”


jQuery how to make the ajax request "synchronous" when async is true

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/可能需要 10 秒甚至更长时间来处理 TDS。

通知栏的预期结果为

我在做 0

我正在做 1

我正在做 2

做!

我得到的实际结果是:

做!

我想这是由 jquery ajax 的异步变量设置为 true 引起的。

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

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

在异步为真的情况下,所有 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)移动到成功回调中。

通常,

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

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

如果你可以使用HTML5元素,请使用<progress>元素,这就是他在那里的原因。
增加每个 ajax 请求的成功回调中的进度条值。

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

现场演示

这是解决方案,你应该看看 jQuery deffered 对象

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

你写的响应会发生。改变

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 调用,则应使用 jQuery 延迟对象来管理此调用。

我在这里总结了一个例子 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);