链ajax并按顺序执行。 Jquery延期

我有3个需要ajax才能完成的进程。 但它是异步的,它无法做我想做的事情..

让我们说:

function a(param1, param2) { $.post(..., function(result){ if(result){ b(); } else { console.log("failed a"); } }) } function b() { $.post(..., function(result){ if(result){ c(); } else { console.log("failed b"); } }) } function c() { $.post(..., function(result){ if(result){ console.log("successful"); } else { console.log("failed b"); } }) } 

我希望它像这样执行

 a b c 

正如你所看到的那样,该代码将完美地运行..但是如果使用循环。

  var data = [{param1 : 1235, param2: 3214}, {param1 : 5432, param2: 9876}]; $.each(data, function(k,v){ a(v.param1, v.param2) }); 

它不会按预期工作,只会这样做:

 a a b b c c 

代替

 a b c a b c 

有很多方法可以写出这种东西。

灵活的方法是与“序列”分开的“行动”,允许:

  • 函数a,b,c用于启动异步(ajax)动作,而不知道它们是如何排序的
  • a,b,c可重复使用,作为一个或多个序列的一部分或根据需要单独使用。

这是一种编码这种方法的方法,使用.then()专门用于链接逻辑:

 function a() { return $.post(...).then(function(result) { if(result) return result;//continue on "success" path. else return $.Deferred().reject('a').promise();//convert success to failure. }, function() { return 'a';//continue on failure path. }); } function b() { return $.post(...).then(function(result) { if(result) return result;//continue on "success" path. else return $.Deferred().reject('b').promise();//convert success to failure. }, function() { return 'b';//continue on failure path. }); } function c() { return $.post(...).then(function(result) { if(result) return result;//continue on "success" path. else return $.Deferred().reject('c').promise();//convert success to failure. }, function() { return 'c';//continue on failure path. }); } a().then(b).then(c).then(function() { console.log("successful"); }, function(id) { console.log("failed: " + id); }); 

或者,如果你想拥有一个异步函数, a ,从循环中调用,那么代码可能是这样的:

 function a(obj) { return $.post(...).then(function(result) { if(result) return result;//continue on "success" path. else return $.Deferred().reject(obj.id).promise();//convert success to failure. }, function() { return obj.id;//continue on failure path. }); } var data = [{id:'A', param1:1235, param2:3214}, {id:'B', param1:5432, param2:9876}]; //Note how IDs are included so these data objects can be identified later in failure cases. var dfrd = $.Deferred();//starter Deferred for later resolution. var p = dfrd.promise();//A promise derived from the starter Deferred, forming the basis of a .then() chain. //Build a .then() chain by assignment $.each(data, function(i, obj) { p = p.then( function() { return a(obj); });//By not including a fail handler here, failures will pass straight through to be handled by the terminal .then()'s fail handler. }); //Chain a terminal .then(), with success and fail handlers. p.then(function() { console.log("successful"); }, function(id) { console.log("failed: " + id); }); dfrd.resolve();//Resolve the starter Deferred to get things started. 

你可以使用jQuery的延迟对象和使用’then’链接异步调用,如ajax调用。

你也可以改变它来使用返回延迟的promise对象的函数,而不是像我在我的例子中那样的ajax调用。

http://jsfiddle.net/q4cFv/

(异步函数示例: http : //jsfiddle.net/q4cFv/1/ )

 $(function() { var delay = 3, span = $('span'), posts = [ { input1: 'My name 1', input2: 'My address 1', input3: 'My country 1' }, { input1: 'My name 2', input2: 'My address 2', input3: 'My country 2' }, { input1: 'My name 3', input2: 'My address 3', input3: 'My country 3' }, { input1: 'My name 4', input2: 'My address 4', input3: 'My country 4' } ], looper = $.Deferred().resolve(); $.each(posts, function(i, data) { looper = looper.then(function() { return $.ajax({ data: { json: JSON.stringify(data), delay: delay }, method: 'post', url: '/echo/json/', dataType: 'json' }).done(function(response) { span.append('Response:
'); for(key in response) { span.append(key + ': ' + response[key] + '
'); } $('span').append('Waiting ' + delay + ' seconds

'); }); }); }); });

我看到c不依赖于b结果,而b不依赖于结果。

遵循GRASP原则( http://en.wikipedia.org/wiki/GRASP_(object-oriented_design) ,一定不能知道bb必须不知道c

当我们编程时,要记住GRASP原则或指南非常重要。

高内聚和低耦合意味着我们的代码将更好,更可重用并且更易于维护。

知道abc的主要函数必须构建链式调用。

function将是:

  function a(param1, param2) { var deferred = $.Deferred(); console.log(" function a: begin. Params " + param1 + " and " + param2); mockPost("a_url").done(function() { console.log(" function a: end ok. Params " + param1 + " and " + param2); deferred.resolve(); }).fail(function() { console.log(" function a: end fail. Params " + param1 + " and " + param2); deferred.reject(); }); return deferred.promise(); } function b() { var deferred = $.Deferred(); console.log(" function b: begin"); mockPost("b_url").done(function() { console.log(" function b: end ok."); deferred.resolve(); }).fail(function() { console.log(" function b: end fail."); deferred.reject(); }); return deferred.promise(); } function c() { // We suppose that c function calls to post function and anything more return mockPost("c_url"); } 

主要function是:

  // Array with params for a function (a function is the first link in chain) var data = [{param1 : 1235, param2: 3214}, {param1 : 5432, param2: 9876}]; // Array with calls to each fixed sequence a, b, and c. We iterate over data array var arrayFunctions = []; $.each(data, function(i,obj) { arrayFunctions.push( function() { console.log("Params in data with index " + i + ":"); // We define the fixed sequence: a with params, b without params and c without params return $.iterativeWhen( function() { return a(obj.param1, obj.param2); }, b, c ); } ) }); // Start the global process $.iterativeWhen.apply($, arrayFunctions) .done(function() { console.log ("----------------"); console.log ("> Global Success"); }) .fail(function() { console.log ("--------------"); console.log ("> Global Fail"); }); 

$ .iterativeWhen jQuery中不存在,所以我已经构建了它。 它适用于jQuery 1.8及更高版本。

 $.iterativeWhen = function () { var deferred = $.Deferred(); var promise = deferred.promise(); $.each(arguments, function(i, obj) { promise = promise.then(function() { return obj(); }); }); deferred.resolve(); return promise; }; 

mockPost函数以成功概率模拟对$ .post的调用:

 function mockPost(url) { var deferred = $.Deferred(); setTimeout(function() { if (Math.random() <= 0.9) { console.log(" request url: " + url + "... ok"); deferred.resolve(); } else { console.log(" request url: " + url + "... fail"); deferred.reject(); } }, 1000); return deferred.promise(); } 

日志输出是:

 Params in data with index 0: function a: begin. Params 1235 and 3214 request url: a_url... ok function a: end ok. Params 1235 and 3214 function b: begin request url: b_url... ok function b: end ok. request url: c_url... ok Params in data with index 1: function a: begin. Params 5432 and 9876 request url: a_url... ok function a: end ok. Params 5432 and 9876 function b: begin request url: b_url... ok function b: end ok. request url: c_url... ok ---------------- > Global Success 

jsFiddle这里: http : //jsfiddle.net/E2tp3/

你的问题是你要一次调用所有的s,但是你想等到第一个循环才能进入下一个循环。 您希望在开始下一个循环之前等待前一个’a’循环完成。

让我们假设a,b,c接受回调,然后传递,

一个看起来像

 function a(param1, param2,callback) { $.post(..., function(result){ if(result){ b(callback); } else { console.log("failed a"); } }) } 

b会像:

 function b(callback) { $.post(..., function(result){ if(result){ c(callback); } else { console.log("failed b"); } }) } 

而c看起来像:

 function c(callback) { $.post(..., function(result){ if(result){ console.log("successful"); } else { console.log("failed b"); } callback(); }) } 

这让我们知道周期何时完成。 这让我们写:

 var data = [{param1 : 1235, param2: 3214}, {param1 : 5432, param2: 9876}]; var index = 0; (function updateData(){ a(data[index].param1,data[index].param2,function(){ //call a with the data index++;//update the index updateData(); // start the next cycle }); }); 

这是一个非常简单且高效的AJAX链接/队列插件。 它将依次执行ajax方法。

它的工作原理是接受一组方法,然后按顺序执行它们。 它在等待响应时不会执行下一个方法。

// —这部分是你的代码———————–

$(document).ready(function(){

 var AjaxQ = []; AjaxQ[0] = function () { AjaxMethod1(); } AjaxQ[1] = function () { AjaxMethod2(); } AjaxQ[3] = function () { AjaxMethod3(); } //Execute methods in sequence $(document).sc_ExecuteAjaxQ({ fx: AjaxQ }); 

});

// —这部分是AJAX PLUGIN ——————-

$ .fn.sc_ExecuteAjaxQ = function(options){

 //? Executes a series of AJAX methods in dequence var options = $.extend({ fx: [] //function1 () { }, function2 () { }, function3 () { } }, options); if (options.fx.length > 0) { var i = 0; $(this).unbind('ajaxComplete'); $(this).ajaxComplete(function () { i++; if (i < options.fx.length && (typeof options.fx[i] == "function")) { options.fx[i](); } else { $(this).unbind('ajaxComplete'); } }); //Execute first item in queue if (typeof options.fx[i] == "function") { options.fx[i](); } else { $(this).unbind('ajaxComplete'); } } 

}