Comment enchainer trois appels asynchrones en utilisant jQuery promises?
j'ai trois appels HTTP que je dois faire de manière synchrone et comment puis-je transmettre des 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 je suis venu avec une solution partielle. Puis-je étendre à être pour les 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)})
10 réponses
dans chaque cas, retourner l'objet jqXHR retourné par $.ajax()
.
ces objets sont compatibles avec les promesses et peuvent donc être enchaînés avec .then()
/ .done()
/ .fail()
/ .always()
.
.then()
est celui que vous souhaitez 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);
}
Arguments data
, textStatus
et jqXHR
naître de la $.ajax()
appel à la fonction précédente, c'est à dire. first()
flux second()
et second()
flux third()
.
DEMO (avec $.when('foo')
pour délivrer une promesse remplie, à la place de $.ajax(...)
).
il y a en fait une approche beaucoup plus facile en utilisant des 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
});
enchaînez simplement tous vos appels dans les $.lorsque.(.. appeler ) et de gérer le retour des valeurs dans la .faire.(..) appeler.
Voici une visite si vous préférez: http://collaboradev.com/2014/01/27/understanding-javascript-promises-in-jquery /
assez tard pour répondre, mais je suppose que les réponses manquent un code simple pour enchaîner. Enchaîner des événements est assez simple avec le soutien de promesse en jquery. J'utilise ce qui suit pour le chaînage:
$.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 avec pas compliqué pour les boucles ou les callbacks imbriqués multiples.
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 enchaî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 laid, mais qui fonctionne probablement. Il diffuse le résultat de chaque méthode comme une" mise à jour de progression " sur l'objet de promesse retourné.
$.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();
};
comment l'utiliser dans 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 juste assigner cette variable d'id de first
fonction.
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 des 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 ceci est de faire une fonction réutilisable pour ceci. 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 callbacks qui renvoie un objet promise, comme vos trois fonctions.
exemple d'usage:
chainPromises([first, second, third]).then(function (result) {
console.log('All done! ', result);
});
de Cette façon, le résultat de first
seront automatiquement le paramètre de second
, donc ce qui se passe essentiellement est ceci:
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 au tableau que vous voulez.
À la chaîne d'ajax de jquery appels que j'ai fait :
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();
})
});
j'ai eu le même problème, enchaîner les appels ajax. Après quelques jours d'essais j'ai finalement fait $.ajax({ async: false,...
ce que complètement fait ce que je voulais obtenir. J'ai juste pas fait penser à ça. Ça pourrait aider les autres...