我需要以同步方式进行三次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)})
答案 0 :(得分:77)
在每种情况下,返回$.ajax()
返回的jqXHR对象。
这些对象与Promise兼容,因此可以与.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);
}
参数data
,textStatus
和jqXHR
来自前一个函数中的$.ajax()
调用,即。 first()
Feed second()
和second()
Feed third()
。
DEMO ($.when('foo')
代表$.ajax(...)
提供履行承诺。
答案 1 :(得分:34)
使用jQuery的promises时实际上有一种更简单的方法。看看以下内容:
$.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/
答案 2 :(得分:22)
很晚才回复,但我猜答案缺少一些直接的链接代码。链接事件非常简单,在jquery中有promise支持。我使用以下链接:
$.ajax()
.then(function(){
return $.ajax() //second ajax call
})
.then(function(){
return $.ajax() //third ajax call
})
.done(function(resp){
//handle final response here
})
它很简单,没有复杂的for循环或多个嵌套回调。
答案 3 :(得分:13)
这比那简单得多。
$.ajax
已经返回一个promise(Deferred对象),所以你可以简单地写
function first() {
return $.ajax(...);
}
答案 4 :(得分:4)
我在这里找到了一个好看的解决方案:How do I chain a sequence of deferred functions in jQuery 1.8.x?
这是我自己的类似方法的实现,有点难看,但可能正在工作。它将每个方法的结果作为返回的promise对象的“progress update”广播。
$.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, ...);
}
答案 5 :(得分:4)
您可以用更实用的方式编写它:
[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)
答案 6 :(得分:1)
以下似乎有效并且允许功能列表是动态的:
<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>
&#13;
答案 7 :(得分:1)
执行此操作的最佳方法是为此创建可重用的功能。这甚至可以使用reduce
只需一行代码来完成:
function chainPromises(list) {
return list.reduce((chain, func) => chain ? chain.then(func) : func(), null);
}
此函数接受一个返回promise对象的回调数组,就像你的三个函数一样。
使用示例:
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) });
当然,你可以根据需要为数组添加任意数量的函数。
答案 8 :(得分:-1)
链接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();
})
});
答案 9 :(得分:-3)
我遇到了同样的问题,链接了ajax调用。经过几天的尝试,我终于做到了$.ajax({ async: false,...
什么完全做了我想要的。我没想到这一点。它可能会帮助别人......