Comme d’autres avant moi, j’ai du mal à utiliser scope en Javascript. (Ça et essayer de lire les trucs putains). J’ai vérifié certaines des discussions précédentes sur cette question, mais je n’arrive pas à les faire appliquer correctement à mon émission. Dans l’exemple ci-dessous, je souhaite manipuler les valeurs du tableau tagsArr
, une fois celui-ci complètement tagsArr
. J’ai déclaré la variable tagsArr en dehors du champ de la fonction dans laquelle elle est remplie afin de pouvoir y accéder globalement. Mais la variable ne semble pas avoir la scope que j’attendais – tagsArr.length
est 0 au point où j’appelle la sortie de la console sur la ligne 16.
$(function(){ var apiKey = [myapikey]; var tags = ''; var tagsArr = new Array(); $.getJSON('http://api.flickr.com/services/rest/?&method=flickr.people.getPublicPhotos&api_key=' + apiKey + '&user_id=46206266@N05&extras=date_taken,tags&format=json&jsoncallback=?', function(data){ $.each(data.photos.photo, function(i, item) { var photoID = item.id; $.getJSON('http://api.flickr.com/services/rest/?&method=flickr.photos.getInfo&api_key=' + apiKey + '&photo_id=' + photoID + '&format=json&jsoncallback=?', function(data){ if (data.photo.tags.tag != '') { $.each(data.photo.tags.tag, function(j, item) { tagsArr.push(item.raw); }); } }); tags = tagsArr.join('
'); console.debug(tagsArr.length); }); $('#total-dragged').append(data.photos.total); $('#types-dragged').append(tags); }); });
Vos appels à getJSON sont asynchrones. Par conséquent, tous les appels au getJSON interne seront toujours en attente au moment où la ligne console.debug sera atteinte. Par conséquent, la longueur du tableau est toujours 0.
Vous devez exécuter du code supplémentaire une fois l’appel final getJSON terminé.
$(function(){ var apiKey = [myapikey]; var tags = ''; var tagsArr = new Array(); $.getJSON('http://api.flickr.com/services/rest/?&method=flickr.people.getPublicPhotos&api_key=' + apiKey + '&user_id=46206266@N05&extras=date_taken,tags&format=json&jsoncallback=?', function(data){ var totalExpected = data.photos.total; var totalFetched = 0; $.each(data.photos.photo, function(i, item) { var photoID = item.id; $.getJSON('http://api.flickr.com/services/rest/?&method=flickr.photos.getInfo&api_key=' + apiKey + '&photo_id=' + photoID + '&format=json&jsoncallback=?', function(data){ if (data.photo.tags.tag != '') { $.each(data.photo.tags.tag, function(j, item) { tagsArr.push(item.raw); totalFetched += 1; if (totalFetched == totalExpected) fetchComplete(); }); } }); function fetchComplete() { tags = tagsArr.join('
'); console.debug(tagsArr.length); } }); $('#total-dragged').append(data.photos.total); $('#types-dragged').append(tags); }); });
Cela fonctionne en supposant que le nombre total de photos ne dépasse pas la valeur par défaut de 100 par page, sinon vous auriez besoin de le modifier.
Cela dit, je ne pense pas que l’utilisation de .each pour lancer un grand nombre de requêtes getJSON ait beaucoup de sens. Je le refactoriserais de sorte qu’un seul appel à getJSON soit en attente à la fois. Laissez le rappel d’un numéro le prochain getJSON pour la photo suivante jusqu’à ce que tous aient été extraits, puis créez votre code complet.
$ .getJSON est asynchrone (le a en ajax). Cela signifie qu’au moment où vous arrivez à console.debug (), getJSON est toujours en cours d’obtention. Vous aurez besoin de faire un travail supplémentaire dans le rappel JSON.
La raison en est que getJSON
est une requête asynchrone. après l’appel de $.getJSON
, le moteur javascript passera immédiatement aux deux lignes de code suivantes et affichera la longueur de votre tableau, qui est alors nulle. Ce n’est qu’après cela que la demande getJSON
reçoit une réponse et ajoute des éléments au tableau.
La fonction getJSON est asynchrone. Par conséquent, lorsque vous appelez la fonction debug, le tableau est toujours vide car les demandes ne sont pas terminées. Utilisez la fonction $ .ajax et définissez async: false et cela fonctionnera.
$.ajax({ type: "GET", url: 'http://api.flickr.com/services/rest/?&method=flickr.photos.getInfo&api_key=' + apiKey + '&photo_id=' + photoID + '&format=json&jsoncallback=?', dataType: "json", async:false, success:function(data){ if (data.photo.tags.tag != '') { $.each(data.photo.tags.tag, function(j, item) { tagsArr.push(item.raw); }); } } });
Ce n’est pas un problème de scope – le problème est que getJSON
est asynchrone, il continue donc à s’exécuter immédiatement après l’envoi de la demande à flickr. Au moment où le navigateur exécute console.debug
la demande n’est pas renvoyée et vous n’avez pas fini de traiter la réponse (et n’avez donc encore placé aucun élément dans le tableau).
Pour résoudre ce problème, recherchez tout le code à exécuter uniquement lorsque le tableau est plein et déplacez-le dans votre méthode de rappel getJSON
:
if (data.photo.tags.tag != '') { $.each(data.photo.tags.tag, function(j, item) { tagsArr.push(item.raw); }); tags = tagsArr.join('
'); console.debug(tagsArr.length); $('#total-dragged').append(data.photos.total); $('#types-dragged').append(tags); }
Vous voudrez peut-être vérifier la réponse à cette question que j’ai postée . Il existe de bonnes informations sur les problèmes de scope en javascript.