可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have three HTTP calls that need I need to make in a synchronous manner and how do I pass data from one call to the other?
function first()
{
ajax()
}
function second()
{
ajax()
}
function third()
{
ajax()
}
function main()
{
first().then(second).then(third)
}
I tried to use the deferred for the two functions and I came up with a partial solution. Can I extend it to be for three functions?
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:
In each case, return the jqXHR object returned by $.ajax()
.
These objects are Promise-compatible so can be chained with .then()
/.done()
/.fail()
/.always()
.
.then()
is the one you want in this case, exactly as in the question.
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);
}
Arguments data
, textStatus
and jqXHR
arise from the $.ajax()
call in the previous function, ie. first()
feeds second()
and second()
feeds third()
.
DEMO (with $.when(\'foo\')
to deliver a fulfilled promise, in place of $.ajax(...)
).
回答2:
There is actually a much easier approach when using promises with jQuery. Have a look at the following:
$.when(
$.ajax(\"/first/call\"),
$.ajax(\"/second/call\"),
$.ajax(\"/third/call\")
)
.done(function(first_call, second_call, third_call){
//do something
})
.fail(function(){
//handle errors
});
Simply chain all your calls into the $.when(...) call and handle the return values in the .done(...) call.
Here\'s a walkthrough if you prefer: http://collaboradev.com/2014/01/27/understanding-javascript-promises-in-jquery/
回答3:
Quite late to reply, but I guess answers are missing some straight forward code for chaining. Chaining events is pretty simple with promise support in jquery. I use the following for chaining:
$.ajax()
.then(function(){
return $.ajax() //second ajax call
})
.then(function(){
return $.ajax() //third ajax call
})
.done(function(resp){
//handle final response here
})
It\'s simple with no complicated for loops or multiple nested callbacks.
回答4:
It\'s much simpler than that.
$.ajax
already returns a promise (Deferred object), so you can simply write
function first() {
return $.ajax(...);
}
回答5:
You can write it in more functional manner:
[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:
I found a good looking solution here: How do I chain a sequence of deferred functions in jQuery 1.8.x?
And here is my own implementation of similar approach, somewhat ugly but probably working. It broadcasts result of each method as a «progress update» on returned promise object.
$.chain = function() {
var def = $.Deferred();
var funcs = arguments;
var left = arguments.length;
function next() {
if(left == 0) {
def.resolve();
return;
}
var func = funcs[funcs.length - left]; // current func
var prom = func(ret).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) {
def.notify({
idx: funcs.length-left,
left: left,
result: ret,
success: true,
});
}).fail(function(ret) {
def.notify({
idx: funcs.length-left,
left: left,
result: ret,
success: false,
});
}).always(function(ret) {
next(ret);
});
}
next();
return def.promise();
};
How to use it for your situation? Maybe not beautiful, but it should work:
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\');
});
Or you can just assign that id variable from first
function.
Or if you only need previous function\'s result, you can use this approach:
function first() {
return ajax(...);
}
function second(first_ret) {
return ajax(first_ret.id, ...);
}
function third(second_ret) {
return ajax(second_ret.something, ...);
}
回答7:
The following appears to work and allows the list of functions to be dynamic:
<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>
回答8:
The best way to do this is by making a reusable function for this. This can even be done with just one line of code using reduce
:
function chainPromises(list) {
return list.reduce((chain, func) => chain ? chain.then(func) : func(), null);
}
This function accepts an array of callbacks which return a promise object, like your three functions.
Example usage:
chainPromises([first, second, third]).then(function (result) {
console.log(\'All done! \', result);
});
This way the result of first
will also automatically be the parameter of second
, so basically what happens is this:
first().then(function(res1) { return second(res1) })
.then(function(res2) { return third(res2) })
.then(function(result) { console.log(\'All done! \', result) });
And of course you could add as many functions to the array as you want.
回答9:
To chain jquery ajax calls i did :
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();
})
});
回答10:
I just had the same problem, chaining ajax calls. After a few days of trying I finally did $.ajax({ async: false,...
what completely did what I wanted to archieve. I just not did think of that. It might help others...