J'ai trois appels HTTP que je dois effectuer de manière synchrone et comment puis-je transmettre les données d'un appel à l'autre?
function first()
{
ajax()
}
function second()
{
ajax()
}
function third()
{
ajax()
}
function main()
{
first().then(second).then(third)
}
J'ai essayé d'utiliser le différé pour les deux fonctions et j'ai proposé une solution partielle. Puis-je l'étendre à trois fonctions?
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)})
Dans chaque cas, retourne l'objet jqXHR renvoyé par $.ajax()
.
Ces objets sont compatibles avec Promise et peuvent donc être chaînés avec .then()
/.done()
/.fail()
/.always()
.
.then()
est celui que vous voulez dans ce cas, exactement comme dans la 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);
}
Les arguments data
, textStatus
et jqXHR
découlent de l'appel $.ajax()
de la fonction précédente, c'est-à-dire. first()
alimente second()
et second()
alimente third()
.
DÉMO (avec $.when('foo')
pour tenir une promesse remplie , à la place de $.ajax(...)
).
Il existe en fait une approche beaucoup plus simple lorsque vous utilisez les promesses avec jQuery. Regardez ce qui suit:
$.when(
$.ajax("/first/call"),
$.ajax("/second/call"),
$.ajax("/third/call")
)
.done(function(first_call, second_call, third_call){
//do something
})
.fail(function(){
//handle errors
});
Il vous suffit de chaîner tous vos appels dans l'appel $ .when (...) et de gérer les valeurs de retour dans l'appel .done (...).
Voici une procédure si vous préférez: http://collaboradev.com/2014/01/27/understanding-javascript-promises-in-jquery/
Assez tard pour répondre, mais j'imagine qu'il manque un code simple pour chaîner. Le chaînage d'événements est assez simple avec un support de promesse dans jQuery. J'utilise les éléments suivants pour chaîner:
$.ajax()
.then(function(){
return $.ajax() //second ajax call
})
.then(function(){
return $.ajax() //third ajax call
})
.done(function(resp){
//handle final response here
})
C'est simple, sans boucles for complexes ou plusieurs rappels imbriqués.
C'est beaucoup plus simple que ça.
$.ajax
renvoie déjà une promesse (objet différé), vous pouvez donc simplement écrire
function first() {
return $.ajax(...);
}
Vous pouvez l'écrire de manière plus fonctionnelle:
[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)
J'ai trouvé une bonne solution ici: Comment chaîner une séquence de fonctions différées dans jQuery 1.8.x?
Et voici ma propre mise en œuvre d'une approche similaire, un peu laide mais probablement efficace. Il diffuse le résultat de chaque méthode en tant que "mise à jour de la progression" sur l'objet de promesse retourné.
$.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();
};
Comment l'utiliser pour votre situation? Peut-être pas beau, mais ça devrait marcher:
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');
});
Ou vous pouvez simplement assigner cette variable id à partir de la fonction first
.
Ou si vous n'avez besoin que du résultat de la fonction précédente, vous pouvez utiliser cette approche:
function first() {
return ajax(...);
}
function second(first_ret) {
return ajax(first_ret.id, ...);
}
function third(second_ret) {
return ajax(second_ret.something, ...);
}
Ce qui suit semble fonctionner et permet à la liste de fonctions d’être dynamique:
<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>
La meilleure façon de faire est de créer une fonction réutilisable pour cela. Cela peut même être fait avec une seule ligne de code en utilisant reduce
:
function chainPromises(list) {
return list.reduce((chain, func) => chain ? chain.then(func) : func(), null);
}
Cette fonction accepte un tableau de rappels qui renvoie un objet de promesse, comme vos trois fonctions.
Exemple d'utilisation:
chainPromises([first, second, third]).then(function (result) {
console.log('All done! ', result);
});
De cette façon, le résultat de first
sera aussi automatiquement le paramètre de second
, donc voici ce qui se passe:
first().then(function(res1) { return second(res1) })
.then(function(res2) { return third(res2) })
.then(function(result) { console.log('All done! ', result) });
Et bien sûr, vous pouvez ajouter autant de fonctions que vous le souhaitez au tableau.