How do I chain three asynchronous calls using jQuery promises?
我有三个HTTP调用需要以同步方式进行,如何将数据从一个调用传递到另一个调用?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20  | function first() { ajax() } function second() { ajax() } function third() { ajax() } function main() { first().then(second).then(third) }  | 
我尝试对这两个函数使用deferred,并提出了一个局部解。我可以把它扩展到三个功能吗?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27  | function first() { var deferred = $.Deferred(); $.ajax({ "success": function (resp) { deferred.resolve(resp); }, }); return deferred.promise(); } function second(foo) { $.ajax({ "success": function (resp) { }, "error": function (resp) { } }); } first().then(function(foo){second(foo)})  | 
在每种情况下,返回
这些对象承诺兼容,因此可以与
在这种情况下,你想要的就是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  | function first() { return $.ajax(...); } function second(data, textStatus, jqXHR) { return $.ajax(...); } function third(data, textStatus, jqXHR) { return $.ajax(...); } function main() { first().then(second).then(third); }  | 
参数
演示(用
在jquery中使用承诺实际上有一种更简单的方法。请看以下内容:
1 2 3 4 5 6 7 8 9 10 11  | $.when( $.ajax("/first/call"), $.ajax("/second/call"), $.ajax("/third/call") ) .done(function(first_call, second_call, third_call){ //do something }) .fail(function(){ //handle errors });  | 
只需将所有调用链接到$.when(…)调用中,并处理.done(…)调用中的返回值。
如果您愿意,这里有一个演练:http://collaboradev.com/2014/01/27/understanding-javascript-promises-in-jquery/
回答很晚,但我想答案缺少一些直接链接的代码。通过jquery中的Promise支持,链接事件非常简单。我使用以下链接:
1 2 3 4 5 6 7 8 9 10  | $.ajax() .then(function(){ return $.ajax() //second ajax call }) .then(function(){ return $.ajax() //third ajax call }) .done(function(resp){ //handle final response here })  | 
它很简单,没有复杂的循环或多个嵌套回调。
比那简单多了。
1 2 3  | function first() { return $.ajax(...); }  | 
你可以用更实用的方式来写:
1 2 3 4 5 6 7 8  | [function() { return ajax(...)}, function(data) { return ajax(...)}] .reduce(function(chain, callback) { if(chain) { return chain.then(function(data) { return callback(data); }); } else { return callback(); } }, null)  | 
我在这里找到了一个很好的解决方案:如何在jquery 1.8.x中链接一系列延迟函数?
这里是我自己实现的类似方法,有点难看,但可能有效。它将每个方法的结果作为一个?进度更新?&在返回的承诺对象上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36  |   $.chain = function() { var defer = $.Deferred(); var funcs = arguments; var left = funcs.length; function next(lastResult) { if(left == 0) { defer.resolve(); return; } var func = funcs[funcs.length - left]; // current func var prom = func(lastResult).promise(); // for promise will return itself, // for jquery ojbect will return promise. // these handlers will be launched in order we specify them prom.always(function() { left--; }).done(function(ret) { defer.notify({ idx: funcs.length-left, left: left, result: ret, success: true, }); }).fail(function(ret) { defer.notify({ idx: funcs.length-left, left: left, result: ret, success: false, }); }).always(function(ret) { next(ret); }); } next(); return defer.promise(); };  | 
如何在你的情况下使用它?也许不太漂亮,但它应该起作用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20  | function first() { return ajax(...); } var id; funciton second() { return ajax(id, ...); } function third() { return ajax(id, ...); } $.chain(first, second, third).progress(function(p) { if(p.func == first) id = p.result.identifier; }).then(function() { alert('everything is done'); });  | 
或者,您可以从
或者,如果只需要上一个函数的结果,则可以使用以下方法:
1 2 3 4 5 6 7 8 9  | function first() { return ajax(...); } function second(first_ret) { return ajax(first_ret.id, ...); } function third(second_ret) { return ajax(second_ret.something, ...); }  | 
实现这一点的最佳方法是为此创建一个可重用的函数。这甚至可以通过使用
1 2 3  | function chainPromises(list) { return list.reduce((chain, func) => chain ? chain.then(func) : func(), null); }  | 
此函数接受返回Promise对象的回调数组,如三个函数。
示例用法:
1 2 3  | chainPromises([first, second, third]).then(function (result) { console.log('All done! ', result); });  | 
这样,
1 2 3  | first().then(function(res1) { return second(res1) }) .then(function(res2) { return third(res2) }) .then(function(result) { console.log('All done! ', result) });  | 
当然,您可以向数组中添加任意多的函数。
以下功能似乎可以工作,并允许函数列表是动态的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49  | <html> <head> demo chained synchronous calls </head> <body> <script src="http://code.jquery.com/jquery-2.2.4.min.js"> <script type="text/javascript"> function one(parms) { console.log('func one ' + parms); return 1; } function two(parms) { console.log('func two ' + parms); return 2; } function three(parms) { console.log('func three ' + parms); return 3; } function four(parms) { console.log('func four ' + parms); return 4; } var funcs = ['one', 'two', 'three', 'four']; var rvals = [0]; function call_next_func() { if (funcs.length == 0) { console.log('done'); } else { var funcname = funcs.shift(); console.log(funcname); rvals.push(window[funcname](rvals)); call_next_func(); } } $(document).ready(function($){ call_next_func(); }); </body> </html>  | 
要链接jquery ajax调用,我做了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44  | function A(){ return $.ajax({ url: url, type: type, data: data, datatype: datatype, success: function(data) { code here } }); } function B(){ return $.ajax({ url: url, type: type, data: data, datatype: datatype, success: function(data) { code here } }); } function C(){ return $.ajax({ url: url, type: type, data: data, datatype: datatype, success: function(data) { code here } }); } A().done(function(data){ B().done(function(data){ C(); }) });  | 
我也遇到了同样的问题,链接Ajax调用。经过几天的努力,我终于做到了。完全按照我的意愿去做的。我只是没想到。它可能会帮助其他人…