链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/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) ,一定不能知道b和b必须不知道c 。
当我们编程时,要记住GRASP原则或指南非常重要。
高内聚和低耦合意味着我们的代码将更好,更可重用并且更易于维护。
知道a , b和c的主要函数必须构建链式调用。
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'); } }
}