Javascript 等到所有 jQuery Ajax 请求完成?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3709597/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 05:47:54  来源:igfitidea点击:

Wait until all jQuery Ajax requests are done?

javascriptjqueryajax

提问by jamietelin

How do I make a function wait until all jQuery Ajax requests are done inside another function?

如何让函数等待所有 jQuery Ajax 请求在另一个函数内完成?

In short, I need to wait for all Ajax requests to be done before I execute the next. But how?

简而言之,在执行下一个请求之前,我需要等待所有 Ajax 请求完成。但是如何?

回答by Alex

jQuery now defines a when functionfor this purpose.

jQuery 现在为此定义了一个when 函数

It accepts any number of Deferred objects as arguments, and executes a function when all of them resolve.

它接受任意数量的 Deferred 对象作为参数,并在它们全部解析时执行一个函数。

That means, if you want to initiate (for example) four ajax requests, then perform an action when they are done, you could do something like this:

这意味着,如果您想发起(例如)四个 ajax 请求,然后在完成后执行一个操作,您可以执行以下操作:

$.when(ajax1(), ajax2(), ajax3(), ajax4()).done(function(a1, a2, a3, a4){
    // the code here will be executed when all four ajax requests resolve.
    // a1, a2, a3 and a4 are lists of length 3 containing the response text,
    // status, and jqXHR object for each of the four ajax calls respectively.
});

function ajax1() {
    // NOTE:  This function must return the value 
    //        from calling the $.ajax() method.
    return $.ajax({
        url: "someUrl",
        dataType: "json",
        data:  yourJsonData,            
        ...
    });
}

In my opinion, it makes for a clean and clear syntax, and avoids involving any global variables such as ajaxStart and ajaxStop, which could have unwanted side effects as your page develops.

在我看来,它提供了干净清晰的语法,并避免了涉及任何全局变量,例如 ajaxStart 和 ajaxStop,这可能会在您的页面开发过程中产生不必要的副作用。

If you don't know in advance how many ajax arguments you need to wait for (i.e. you want to use a variable number of arguments), it can still be done but is just a little bit trickier. See Pass in an array of Deferreds to $.when()(and maybe jQuery .when troubleshooting with variable number of arguments).

如果您事先不知道需要等待多少个 ajax 参数(即您想使用可变数量的参数),它仍然可以完成,但只是有点棘手。请参阅将延迟数组传递给 $.when()(也可能是jQuery .when 使用可变数量的参数进行故障排除)。

If you need deeper control over the failure modes of the ajax scripts etc., you can save the object returned by .when()- it's a jQuery Promiseobject encompassing all of the original ajax queries. You can call .then()or .fail()on it to add detailed success/failure handlers.

如果您需要更深入地控制 ajax 脚本等的失败模式,您可以保存返回的对象.when()- 它是一个包含所有原始 ajax 查询的 jQuery Promise对象。您可以调用.then().fail()来添加详细的成功/失败处理程序。

回答by Arsen Khachaturyan

If you want to know when allajaxrequests are finished in your document, no matter how many of them exists, just use $.ajaxStopevent this way:

如果您想知道文档中的所有ajax请求何时完成,无论存在多少个请求,只需这种方式使用$.ajaxStop事件:

$(document).ajaxStop(function () {
  // 0 === $.active
});

In this case, neither you need to guess how many requests are happening in the application, that might finish in the future, nor dig into functions complex logic or find which functions are doing HTTP(S)requests.

$.ajaxStophere can also be bound to any HTMLnode that you think might be modified by requst.

在这种情况下,您既不需要猜测应用程序中发生了多少请求,这些请求可能在未来完成,也不需要深入研究函数的复杂逻辑或找出哪些函数正在执行HTTP(S)请求。

$.ajaxStophere 也可以绑定到HTML您认为可能被请求修改的任何节点。



Update:
If you want to stick with ESsyntax, then you can use Promise.allfor known ajaxmethods:

更新:
如果你想坚持使用ES语法,那么你可以将Promise.all用于已知ajax方法:

Promise.all([ajax1(), ajax2()]).then(() => {
  // all requests finished successfully
}).catch(() => {
  // all requests finished but one or more failed
})

An interesting point here is that it works both with Promisesand $.ajaxrequests.

这里有趣的一点是它同时适用于Promises$.ajax请求。

Here is the jsFiddledemonstration.

这是jsFiddle演示。



Update 2:
Yet more recent version using async/awaitsyntax:

更新 2:
使用async/await语法的更新版本:

try {
  const results = await Promise.all([ajax1(), ajax2()])
  // do other actions
} catch(ex) { }

回答by jamietelin

I found a good answerby gnarfmy self which is exactly what I was looking for :)

我通过gnarfmy self找到了一个很好的答案,这正是我正在寻找的 :)

jQuery ajaxQueue

jQuery ajax队列

//This handles the queues    
(function($) {

  var ajaxQueue = $({});

  $.ajaxQueue = function(ajaxOpts) {

    var oldComplete = ajaxOpts.complete;

    ajaxQueue.queue(function(next) {

      ajaxOpts.complete = function() {
        if (oldComplete) oldComplete.apply(this, arguments);

        next();
      };

      $.ajax(ajaxOpts);
    });
  };

})(jQuery);

Then you can add a ajax request to the queue like this:

然后你可以像这样向队列添加一个ajax请求:

$.ajaxQueue({
        url: 'page.php',
        data: {id: 1},
        type: 'POST',
        success: function(data) {
            $('#status').html(data);
        }
    });

回答by BBonifield

NOTE:The above answers use functionality that didn't exist at the time that this answer was written. I recommend using jQuery.when()instead of these approaches, but I'm leaving the answer for historical purposes.

注意:上述答案使用的功能在撰写此答案时尚不存在。我建议使用jQuery.when()而不是这些方法,但我将答案留给历史目的。

-

——

You could probably get by with a simple counting semaphore, although how you implement it would be dependent on your code. A simple example would be something like...

您可能可以通过一个简单的计数信号量来解决,尽管您如何实现它取决于您的代码。一个简单的例子是这样的......

var semaphore  = 0,     // counting semaphore for ajax requests
    all_queued = false; // bool indicator to account for instances where the first request might finish before the second even starts

semaphore++;
$.get('ajax/test1.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // process your custom stuff here
    }
});

semaphore++;
$.get('ajax/test2.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // process your custom stuff here
    }
});

semaphore++;
$.get('ajax/test3.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // process your custom stuff here
    }
});

semaphore++;
$.get('ajax/test4.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // process your custom stuff here
    }
});

// now that all ajax requests are queued up, switch the bool to indicate it
all_queued = true;

If you wanted this to operate like {async: false} but you didn't want to lock the browser, you could accomplish the same thing with a jQuery queue.

如果您希望它像 {async: false} 一样操作但又不想锁定浏览器,则可以使用 jQuery 队列完成相同的操作。

var $queue = $("<div/>");
$queue.queue(function(){
    $.get('ajax/test1.html', function(data) {
        $queue.dequeue();
    });
}).queue(function(){
    $.get('ajax/test2.html', function(data) {
        $queue.dequeue();
    });
}).queue(function(){
    $.get('ajax/test3.html', function(data) {
        $queue.dequeue();
    });
}).queue(function(){
    $.get('ajax/test4.html', function(data) {
        $queue.dequeue();
    });
});

回答by olafure

Use the ajaxStopevent.

使用ajaxStop事件。

For example, let's say you have a loading ...message while fetching 100 ajax requests and you want to hide that message once loaded.

例如,假设您在获取 100 个 ajax 请求时有一个loading...消息,并且您想在加载后隐藏该消息。

From the jQuery doc:

从 jQuery文档

$("#loading").ajaxStop(function() {
  $(this).hide();
});

Do note that it will wait for all ajax requests being done on that page.

请注意,它将等待该页面上完成的所有 ajax 请求。

回答by Jesfre

A little workaround is something like this:

一个小的解决方法是这样的:

// Define how many Ajax calls must be done
var ajaxCalls = 3;
var counter = 0;
var ajaxCallComplete = function() {
    counter++;
    if( counter >= ajaxCalls ) {
            // When all ajax calls has been done
        // Do something like hide waiting images, or any else function call
        $('*').css('cursor', 'auto');
    }
};

var loadPersons = function() {
        // Show waiting image, or something else
    $('*').css('cursor', 'wait');

    var url = global.ctx + '/loadPersons';
    $.getJSON(url, function(data) {
            // Fun things
    })
    .complete(function() { **ajaxCallComplete();** });
};

var loadCountries = function() {
    // Do things
    var url = global.ctx + '/loadCountries';
    $.getJSON(url, function(data) {
            // Travels
    })
    .complete(function() { **ajaxCallComplete();** });
};

var loadCities = function() {
    // Do things
    var url = global.ctx + '/loadCities';
    $.getJSON(url, function(data) {
            // Travels
    })
    .complete(function() { **ajaxCallComplete();** });
};

$(document).ready(function(){
    loadPersons();
    loadCountries();
    loadCities();
});

Hope can be useful...

希望有用...

回答by Stefano

javascript is event-based, so you should never wait, rather set hooks/callbacks

javascript 是基于事件的,所以你不应该等待,而应该设置钩子/回调

You can probably just use the success/complete methods of jquery.ajax

您可能只使用jquery.ajax的成功/完成方法

Or you could use .ajaxComplete:

或者你可以使用.ajaxComplete

$('.log').ajaxComplete(function(e, xhr, settings) {
  if (settings.url == 'ajax/test.html') {
    $(this).text('Triggered ajaxComplete handler.');
    //and you can do whatever other processing here, including calling another function...
  }
});

though youy should post a pseudocode of how your(s) ajax request(s) is(are) called to be more precise...

虽然你应该发布一个伪代码,说明你的 ajax 请求是如何被调用的,以便更精确......

回答by shmuel613

jQuery allows you to specify if you want the ajax request to be asynchronous or not. You can simply make the ajax requests synchronous and then the rest of the code won't execute until they return.

jQuery 允许您指定是否希望 ajax 请求是异步的。您可以简单地使 ajax 请求同步,然后其余代码在它们返回之前不会执行。

For example:

例如:

jQuery.ajax({ 
    async: false,
    //code
});

回答by Sanjeev Kumar Dangi

On the basis of @BBonifield answer, I wrote a utility function so that semaphore logic is not spread in all the ajax calls.

在@BBonifield 回答的基础上,我编写了一个实用程序函数,以便信号量逻辑不会在所有 ajax 调用中传播。

untilAjaxis the utility function which invokes a callback function when all the ajaxCalls are completed.

untilAjax是在所有 ajaxCalls 完成时调用回调函数的实用函数。

ajaxObjsis a array of ajax setting objects [http://api.jquery.com/jQuery.ajax/].

ajaxObjs是一组 ajax 设置对象[http://api.jquery.com/jQuery.ajax/]

fnis callback function

fn是回调函数

function untilAjax(ajaxObjs, fn) {
  if (!ajaxObjs || !fn) {
    return;
  }
  var ajaxCount = ajaxObjs.length,
    succ = null;

  for (var i = 0; i < ajaxObjs.length; i++) { //append logic to invoke callback function once all the ajax calls are completed, in success handler.
    succ = ajaxObjs[i]['success'];
    ajaxObjs[i]['success'] = function(data) { //modified success handler
      if (succ) {
        succ(data);
      }
      ajaxCount--;
      if (ajaxCount == 0) {
        fn(); //modify statement suitably if you want 'this' keyword to refer to another object
      }
    };
    $.ajax(ajaxObjs[i]); //make ajax call
    succ = null;
  };

Example: doSomethingfunction uses untilAjax.

示例:doSomething函数使用untilAjax.

function doSomething() {
  // variable declarations
  untilAjax([{
    url: 'url2',
    dataType: 'json',
    success: function(data) {
      //do something with success data
    }
  }, {
    url: 'url1',
    dataType: 'json',
    success: function(data) {
      //do something with success data
    }
  }, {
    url: 'url2',
    dataType: 'json',
    success: function(response) {
      //do something with success data
    }
  }], function() {
    // logic after all the calls are completed.
  });
}

回答by Fatmuemoo

If you need something simple; once and done callback

如果你需要一些简单的东西;一次完成回调

        //multiple ajax calls above
        var callback = function () {
            if ($.active !== 0) {
                setTimeout(callback, '500');
                return;
            }
            //whatever you need to do here
            //...
        };
        callback();