如何使用 jQuery 承诺链接三个异步调用?

我需要以同步的方式进行三个 HTTP 调用,并且如何将数据从一个调用传递到另一个调用?

function first()
{
ajax()
}


function second()
{
ajax()
}


function third()
{
ajax()
}




function main()
{
first().then(second).then(third)
}

我尝试对这两个函数使用延迟函数,得到了一个部分解决方案。我可以将它扩展为三个函数吗?

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)})
106899 次浏览

比那简单多了。

$.ajax已经返回了一个承诺(延迟对象) ,因此您可以简单地编写

function first() {
return $.ajax(...);
}

在每种情况下,返回由 $.ajax()返回的 jqXHR 对象。

这些对象是承诺兼容的,因此可以与 .then()/.done()/.fail()/.always()链接。

在这种情况下,.then()是您需要的,正如在问题中一样。

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);
}

参数 datatextStatusjqXHR产生于前面函数中的 $.ajax()调用,即。first()供给 second()second()供给 third()

DEMO (用 $.when('foo')代替 $.ajax(...)来实现承诺)。

在使用 jQuery 时,实际上有一种更简单的方法:

$.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 1.8. x 中链接一系列延迟函数?

下面是我自己的类似方法的实现,虽然有点难看,但可能有效。它将每个方法的结果作为返回的承诺对象的“进度更新”进行广播。

  $.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();
};

如何使用它为您的情况? 也许不美观,但它应该工作:

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');
});

或者您可以从 first函数中指定 id 变量。

或者,如果只需要前一个函数的结果,可以使用以下方法:

function first() {
return ajax(...);
}
function second(first_ret) {
return ajax(first_ret.id, ...);
}
function third(second_ret) {
return ajax(second_ret.something, ...);
}

您可以用更实用的方式编写它:

[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)

下列函数似乎可以工作,并允许动态列表:

<html>
<head>
<title>demo chained synchronous calls</title>
</head>
<body>


<script src="http://code.jquery.com/jquery-2.2.4.min.js"></script>
<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();
});
</script>


</body>
</html>

最好的方法是为此创建一个可重用的函数。这甚至可以通过使用 reduce的一行代码来完成:

function chainPromises(list) {
return list.reduce((chain, func) => chain ? chain.then(func) : func(), null);
}

这个函数接受一个回调数组,这个数组返回一个承诺对象,就像你的三个函数一样。

示例用法:

chainPromises([first, second, third]).then(function (result) {
console.log('All done! ', result);
});

这样 first的结果也会自动成为 second的参数,所以基本上会发生这样的情况:

first().then(function(res1) { return second(res1) })
.then(function(res2) { return third(res2)  })
.then(function(result) { console.log('All done! ', result) });

当然,您可以向数组中添加任意多的函数。

现在回答已经很晚了,但是我猜想答案缺少一些直接的链接代码。在 jquery 中支持承诺,链接事件非常简单。我用以下方法来锁链:

$.ajax()
.then(function(){
return $.ajax() //second ajax call
})
.then(function(){
return $.ajax() //third ajax call
})
.done(function(resp){
//handle final response here
})

它很简单,没有复杂的 for 循环或多个嵌套回调。

链接 jquery ajax 调用:

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();
})
});