Indices non définis dans le tableau après les demandes asynchrones

J'ai un peu de difficulté avec un tableau qui est (à l'extérieur d'un appel asynchrone) parfaitement bien défini, mais quand j'appelle ses indices dans une demande asynchrone (p. Ex. $ .getJSON), tous les indices du tableau sont indéfinis mais la longueur est Toujours le même. Voici mon code.

Le tableau auquel je me réfère est FriendsArray

Le tableau a l'indice correct pendant le deuxième appel "$ .getJSON", mais dans le rappel de cette fonction, tous ses indices deviennent indéfinis. Le réseau ne devrait-il pas conserver ses valeurs puisqu'il a été défini dans le cadre de la méthode?

if (response.status === 'connected') { var accessToken = $.trim(response.authResponse.accessToken); var hashArray = []; var friendArray = []; document.getElementById("statusCheck").innerHTML = accessToken; $.getJSON('https://graph.facebook.com/me/friends?access_token=' + accessToken, function(dataJSON){ hashArray = dataJSON['data']; for (var i = 0; i < hashArray.length; i++){ friendArray.push(hashArray[i]["id"]); } var resultJSON = "{"; var resultArray = []; for (var i = 0; i < friendArray.length; i++){ $.getJSON('https://graph.facebook.com/me/mutualfriends/' + friendArray[i] + "?access_token=" + accessToken, function(dataJSON2){ resultArray = dataJSON2['data']; resultJSON += friendArray[i] + ":" + resultArray.length + ","; //alert(resultJSON); }) if (i == friendArray.length - 1){ postArrayPopulation(resultJSON); } } }); 

}

Le problème est que la fonction de rappel arrive quelque temps plus tard lorsque la fonction ajax est terminée. À ce moment-là, l'index du tableau a avancé jusqu'à la fin de votre boucle for (donc il pointe la fin du tableau) à une valeur indéfinie. Le tableau est toujours là, mais votre index a été modifié au moment où la fonction d'achèvement est appelée.

La technique habituellement utilisée pour obtenir l'indice dans le gestionnaire de succès est de le capturer dans une fermeture de fonction où il est capturé pour une utilisation dans la fonction d'achèvement.

Vous pouvez créer une fermeture qui capture la valeur de l'indice en remplaçant votre gestionnaire de succès par ceci:

 (function(index) { return function(dataJSON2) { resultArray = dataJSON2['data']; resultJSON += friendArray[index] + ":" + resultArray.length + ","; //alert(resultJSON); } }) (i); 

Cette fonction externe exécute et crée une fermeture qui saisit la valeur de i et la rend exclusivement disponible pour le gestionnaire de réussite. Lorsqu'il s'exécute automatiquement, il renvoie votre gestionnaire de succès qui est ainsi passé à la fonction getJSON à appeler plus tard. Mais, lorsqu'on l'appelle plus tard, la valeur de i dont vous avez besoin est disponible pour le gestionnaire de succès via l'argument dans la fonction d'auto-exécution.

Voici une autre façon de penser aux fermetures utilisées avec les rappels.

  1. Toute fonction a accès à toutes les variables qui sont dans le champ d'application lorsqu'il est déclaré, même des variables qui se situent à un niveau supérieur dans les étendues parentales et même si la fonction est appelée plus tard comme rappel. C'est en fait une énorme fonctionnalité de javascript que beaucoup d'autres langues n'ont pas.
  2. Donc, si nous voulons qu'une variable soit disponible pour une fonction de rappel plus tard, lorsque le rappel est exécuté, nous devons simplement obtenir cette variable dans la portée de cette fonction de rappel.

Voici un exemple de ceci:

 function cycleOnOff(sel, cnt, delay) { var obj = $(sel); function next() { if (cnt-- > 0) { obj.toggle(); setTimeout(next, delay); } } next(); } 

Dans ce cas, la fonction next() est un rappel pour setTimeout() , mais cette fonction a un accès complet aux variables dans sa portée parentale: sel , cnt , delay et obj .

  1. Si la variable ne change pas entre le moment où le rappel est initialement réglé et lorsque le rappel est appelé, alors c'est assez simple. Vous pouvez simplement utiliser une déclaration de fonction anonyme et toutes les variables de portée supérieure disponibles au moment de la définition de la fonction anonyme seront toujours disponibles lorsque le rappel sera appelé ultérieurement.
  2. Si la variable change à mesure que le code continue à s'exécuter et que vous souhaitez créer une valeur spécifique qu'il est maintenant disponible pour le rappel quand il est appelé plus tard – c'est quand il devient un peu plus délicat. Ce que l'on peut faire, c'est créer une fonction dans laquelle vous passez cette variable, créant ainsi une portée où cette variable a la valeur souhaitée et où elle ne changera pas lorsque l'autre code continue à s'exécuter. Mais, parce que ce que nous voulons, c'est une fonction de rappel, pas seulement un appel de fonction, nous devons combiner les deux de façon semi-étrange. Nous faisons un appel de fonction et lui passons la valeur souhaitée. Dans cet appel de fonction, nous renvoyons une référence à notre fonction de rappel. Cela affecte la fonction de rappel de manière appropriée, mais il met la fonction de rappel dans une fermeture qui capture la valeur de notre variable souhaitée. Encore mieux, cette fermeture est unique à cette instance particulière du rappel, de sorte que chaque utilisation du rappel aura sa propre fermeture et donc sa propre valeur unique de cette variable. La fermeture / rappel que nous avons créée pour votre problème particulier en est un exemple.