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)})
53
demandé sur mdinger 2013-04-16 04:44:15

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(...) ).

71
répondu Beetroot-Beetroot 2014-04-13 00:06:53

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 /

30
répondu user3242460 2014-01-27 23:21:00

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.

17
répondu prajnavantha 2018-05-31 00:18:11

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(...);
}
13
répondu SLaks 2013-04-16 00:47:16

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)
4
répondu Mike Vitik 2016-01-26 15:48:49

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, ...);
}
3
répondu MarSoft 2017-05-23 11:33:24

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>
0
répondu duanev 2016-12-02 23:25:23

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.

0
répondu Duncan Luk 2017-01-29 12:52:58

À 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();
     })
   });
0
répondu Dimitris Kougioumtzis 2018-06-19 19:35:00

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...

-3
répondu MelW 2016-06-13 06:01:34