等待多个asynchronous调用完成后再继续
所以,我有一个页面加载并通过jquery.get做出几个请求来填充下拉列表的值。
$(function() { LoadCategories($('#Category')); LoadPositions($('#Position')); LoadDepartments($('#Department')); LoadContact(); };
然后调用LoadContact(); 哪一个做了另一个调用,当它返回时,它填充表单上的所有字段。 问题是,往往下拉不是全部填充,因此,它不能将它们设置为正确的值。
我需要做的是以某种方式使LoadContact只在其他方法完成且callback完成后才执行。
但是,我不希望在调用LoadContact()之前把一堆标志放在下拉群体callback的最后,然后我再检查,并且必须有一个recursionsetTimeout调用检查。
jQuery中有什么让我说:“当所有这些都完成后执行这个。”?
更多信息我正在思考这方面的事情
$().executeAfter( function () { // When these are done LoadCategories($('#Category')); LoadPositions($('#Position')); LoadDepartments($('#Department')); }, LoadContact // Do this );
…需要跟踪方法执行过程中发生的ajax调用,当它们全部完成时,调用LoadContact;
如果我知道如何拦截正在使用该function的Ajax,我可以写一个jQuery扩展来完成这个function。
我的解决scheme
;(function($) { $.fn.executeAfter = function(methods, callback) { var stack = []; var trackAjaxSend = function(event, XMLHttpRequest, ajaxOptions) { var url = ajaxOptions.url; stack.push(url); } var trackAjaxComplete = function(event, XMLHttpRequest, ajaxOptions) { var url = ajaxOptions.url; var index = jQuery.inArray(url, stack); if (index >= 0) { stack.splice(index, 1); } if (stack.length == 0) { callback(); $this.unbind("ajaxComplete"); } } var $this = $(this); $this.ajaxSend(trackAjaxSend) $this.ajaxComplete(trackAjaxComplete) methods(); $this.unbind("ajaxSend"); }; })(jQuery);
当这个方法被调用的时候,这个绑定到ajaxSend事件上,并且保存一个被调用的url列表( 尽pipe需要一个更好的唯一的id )。 然后它从ajaxSend中解除绑定,所以只跟踪我们关心的请求。 它还会绑定到ajaxComplete,并在返回时从栈中移除项目。 当堆栈达到零时,它执行我们的callback,并解除绑定ajaxComplete事件。
你可以像这样使用.ajaxStop()
$(function() { $(document).ajaxStop(function() { $(this).unbind("ajaxStop"); //prevent running again when other calls finish LoadContact(); }); LoadCategories($('#Category')); LoadPositions($('#Position')); LoadDepartments($('#Department')); });
当所有当前的请求完成后,这将运行,然后解除绑定,如果未来在页面中的Ajax调用执行,它将不会运行。 另外,一定要把它放在你的ajax调用之前,这样它就可以被绑定得更早了,用.ajaxStart()
更重要,但是最好用两个方法来做。
扩展Tom Lianza的答案 , $.when()
.when $.when()
现在比使用.ajaxStop()
更好。
唯一需要注意的是,您需要确保在返回Deferred object
需要等待的asynchronous方法。 幸运的是,jQuery ajax调用已经在默认情况下做到这一点。 所以为了实现这个问题的场景,需要等待的方法看起来像这样:
function LoadCategories(argument){ var deferred = $.ajax({ // ajax setup }).then(function(response){ // optional callback to handle this response }); return deferred; }
然后在所有三个Ajax调用都返回之后调用LoadContact(),并可选地执行各自的callback:
// setting variables to emphasize that the functions must return deferred objects var deferred1 = LoadCategories($('#Category')); var deferred2 = LoadPositions($('#Position')); var deferred3 = LoadDepartments($('#Department')); $.when(deferred1, deferred2, deferred3).then(LoadContact);
如果你在JQuery 1.5或更高版本,我怀疑延期对象是你最好的select: http : //api.jquery.com/category/deferred-object/
辅助方法,什么时候也是相当不错的: http : //api.jquery.com/jQuery.when/
但是,我不希望在调用LoadContact()之前把一堆标志放在下拉群体callback的最后,然后我再检查,并且必须有一个recursionsetTimeout调用检查。
不需要setTimeout。 你只需在每个callback中检查所有三个列表是否被填充(或者更好地设置一个计数器,在每个callback中增加它并等到它等于3),然后从callback调用LoadContact。 对我来说似乎很容易。
ajaxStop方法可能工作,我只是不是很熟悉它。