1

Je sais, il y a déjà beaucoup de questions concernant AJAX et Synchronicity ici, mais je n'ai pas trouvé la bonne réponse à ma cause. S'il vous plaît soyez doux, je suis un noob, donc, cela pourrait être un doublon. Pourtant, même faire allusion à cela pourrait aider moi et d'autres à trouver une réponse appropriée.Plusieurs appels AJAX imbriqués dans jQuery: comment le faire correctement, sans retomber synchrone?

La fonction

$.fn.facebookEvents = function(options){ 
    var fbEvents = 'https://graph.facebook.com/'+options.id+'/events/?access_token='+options.access_token+'&since=now&limit=500'; 
    var events = []; 

    $.when($.getJSON(fbEvents)).then(function(json){ 

     $.each(json.data, function(){ 
      $.getJSON('https://graph.facebook.com/'+this.id+'/?access_token='+options.access_token, function(jsonData){ 
       events.push(jsonData); 
       console.log(events);   // here array "events" is filled successively 
      }); 
       console.log(events);   // here array "events" remains empty 
     }); 

    }).done(function(){ 

     $("#fb_data_live").html(
      $("#fb_events").render(events) 
     ); 

    }); 
}; 

Qu'est-ce qui se passe dans cette fonction, est un appel AJAX (via un raccourci jQuerys getJSON) pour la liste d'événements d'une page Facebook. Cela renverra une liste d'objets JSON représentant chaque date. Exemple d'un objet en guise de réponse:

{ 
    "end_time": "2017-03-16T23:00:00+0100", 
    "location": "Yuca K\u00f6ln", 
    "name": "K\u00f6rner // G\u00e4nsehaut Tour 2017 // K\u00f6ln", 
    "start_time": "2017-03-16T20:00:00+0100", 
    "timezone": "Europe/Berlin", 
    "id": "985939951529300" 
}, 

Malheureusement, il manque des détails dont nous avons besoin. Ils sont cachés (imbriqués) et peuvent être trouvés, après avoir fait un second getJSON (ligne 8 dans la fonction), en utilisant le "id" individuel de chaque objet. Maintenant, les réponses de Facebook:

{ 
    "description": "http://www.eventim.de/koerner\nTickets ab sofort exklusiv auf eventim.de und ab MI 07.09. \u00fcberall wo es Tickets gibt sowie auf contrapromotion.com.", 
    "end_time": "2017-03-16T23:00:00+0100", 
    "is_date_only": false, 
    "location": "Yuca K\u00f6ln", 
    "name": "K\u00f6rner // G\u00e4nsehaut Tour 2017 // K\u00f6ln", 
    "owner": { 
     "name": "K\u00f6rner", 
     "category": "Musician/Band", 
     "id": "366592010215263" 
    }, 
    "privacy": "OPEN", 
    "start_time": "2017-03-16T20:00:00+0100", 
    "timezone": "Europe/Berlin", 
    "updated_time": "2016-09-28T10:31:47+0000", 
    "venue": { 
     "name": "Yuca K\u00f6ln" 
    }, 
    "id": "985939951529300" 
} 

Et voila, les détails que je recherchais. Après avoir effectué ce second appel AJAX (imbriqué), j'appuie sur les données JSON dans le tableau "events" (ligne 12).

Le problème

Cela devrait remplir le tableau avec chaque itération .each. Cependant, jetez un oeil aux deux 'console.logs'. Le premier renvoie le tableau rempli, le second renvoie un tableau vide ... Si les appels AJAX sont faits de manière synchrone (ce qui n'est pas le cas), p. Ex. en ajoutant $.ajaxSetup({async: false}); avant la fonction, cela fonctionne bien cependant. Le tableau est rempli et peut être rendu (ligne 18).

La question

Comment ce comportement s'expliquer et comment cette fonction peut être bien fait? Je sais, il doit y avoir un moyen d'utiliser différé et des promesses? J'ai pensé que je l'ai fait, en utilisant .when.then.done ... évidemment, j'ai commis une erreur.

Avec mes meilleures salutations, Julius

Répondre

1

Il est évident que vous ne savez rien au sujet des promesses. Je suppose que je l'aurais fait autrement, mais en utilisant des promesses, vous pouvez faire ce qui suit:

$.fn.facebookEvents = function(options){ 
    var fbEvents = 'https://graph.facebook.com/'+options.id+'/events/?access_token='+options.access_token+'&since=now&limit=500'; 
    var events = []; 
    var deferred=$.Deferred(); 
    var promises=[]; 
    var done=false; 

    $.when(deferred).then(function(events) { 
     console.log(events); 
    }); 

    $.getJSON(fbEvents).done(function(json){ 
     $.each(json.data, function(){ 
      promises.push($.getJSON('https://graph.facebook.com/'+this.id+'/?access_token='+options.access_token).done(function(jsonData){ 
       events.push(jsonData); 
       var completed=promises.filter(function(element) { return element.state=='pending' }).length==0; 
       if(done&&completed) { 
        deferred.resolve(events); 
       } 
      })); 
     }); 
     done=true; 
    }); 
}; 
0

Merci pour votre réponse. Par souci d'exhaustivité, j'ai proposé une solution alternative.

$.fn.facebookEvents = function(options){ 
    var fbEvents = 'https://graph.facebook.com/'+options.id+'/events/?access_token='+options.access_token+'&since=now&limit=500'; 
    var events = []; 
    var eventsData = []; 
    var i; 

    // first call 
    function A() { 
     return $.getJSON(fbEvents).then(function(json){ 
      events.push(json); 
      i = events[0].data.length; 
     }); 
    }; 

    // second call for objects details 
    function B(resultFromA) { 
     $.each(events[0].data, function(){ 
      $.getJSON('https://graph.facebook.com/'+this.id+'/?access_token='+options.access_token, function(jsonData){     
       eventsData.push(jsonData); 
       i--; 

       if (i == 0){ 
        output(eventsData); 
       }; 
      }); 
     }); 
    }; 

    A().then(B); 

    function output() { 
     //render here 
    }; 

};