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调用。经过几天的努力,我终于做到了。完全按照我的意愿去做的。我只是没想到。它可能会帮助其他人…