2011-07-18 1 views
1

J'utilise l'API Facebook Graph pour obtenir la liste d'amis d'un utilisateur et générer un message d'état basé sur un modèle et des amis aléatoires. Si j'utilise alert(response.data[0].name); au lieu de return(response); mon code fonctionne et je vois le nom du premier ami Facebook. Quand je le prends plus loin dans mon code, il génère une erreur non définie. Sur la base de quelques heures d'efforts pour résoudre le problème, je pense avoir un problème de portée qui ne me permet plus d'utiliser la réponse ou un problème de formatage JSON. J'ai essayé de jouer avec l'analyse JSON de jQuery, mais je n'ai rien gagné de plus.JSON La sortie reste indéfinie dans le code mais l'alerte est correcte, est-ce un problème avec la portée?

shuffle = function(v){ 
    for(var j, x, i = v.length; i; j = parseInt(Math.random() * i), x = v[--i], v[i] = v[j], v[j] = x); 
    return v; 
}; 

function getFriends() { 
    FB.login(function(response) { 
     if (response.session && response.perms) { 
     FB.api('/me/friends', function(response) { 
      return response; 
     }); 
     } 
    } , {perms:'publish_stream'}); 
}; 

function selectFriend(){ 
    var friends = getFriends(); 
    friends = friends.data[0]; 
    var findex = friends.length 
    var randomNumber = (Math.floor(Math.random() * 10) % findex); 
    return(friends[randomNumber].name); 
}; 

function process(status){ 
    status = status[0].toString(); 
    var cindex = status.indexOf("{{friend}}"); 

    while (cindex != -1){ 
     status = status.replace("{{friend}}",selectFriend()); 
     cindex = status.indexOf("{{friend}}"); 
    } 
    return(status); 
}; 

function newStatus(){ 
    var status = [ 
     "This status is named {{friend}}", 
     "This status loves {{friend}} but likes {{friend}} too.", 
     "This status goes by {{friend}} but you can call it {{friend}} if you like.", 
     "This status hates {{friend}}" 
    ]; 

    status = shuffle(status); 
    $('#status').text(process(status)); 
} 

Le code commence par l'appel de newStatus() on click.

EDIT: Voici comment je refactorisé mon code au travail après la réponse de jfriend00:

shuffle = function(v){ 
    for(var j, x, i = v.length; i; j = parseInt(Math.random() * i), x = v[--i], v[i] = v[j], v[j] = x); 
    return v; 
}; 

function newStatus(){ 
    var status = [ 
     "This status is named {{friend}}", 
     "This status loves {{friend}} but likes {{friend}} too.", 
     "This status goes by {{friend}} but you can call it {{friend}} if you like.", 
     "This status hates {{friend}}" 
    ]; 
    status = shuffle(status); 
    status = status[0].toString(); 

    FB.login(function(response) { 
     if (response.session && response.perms) { 
     FB.api('/me/friends', function(response) { 
      var friends = response.data; 
      var findex = friends.length 

      var cindex = status.indexOf("{{friend}}"); 

      while (cindex != -1){ 
       var randomNumber = (Math.floor(Math.random() * 10) % findex); 
       var name = friends[randomNumber].name; 

       status = status.replace("{{friend}}",name); 
       cindex = status.indexOf("{{friend}}"); 
      } 
      $('#status').text(status); 
     }); 
     } 
    } , {perms:'publish_stream'}); 
} 

Répondre

2

La question est sans doute que les appels au FB api sont asynchrone. Cela signifie que lorsque vous appelez FB.api(), il lance un appel ajax à FB. Votre autre code continue de s'exécuter pendant que l'appel ajax est en cours. En fait, votre appel à getFriends se termine et le reste de selectFriend() s'exécute également avant que l'appel FB ajax ne soit terminé. Puis, lorsque l'appel API FB est terminé, il appelle la fonction d'achèvement (probablement où vous avez placé une alerte). Dans votre code, vous ne faites rien de significatif dans la fonction d'achèvement. Vous venez de renvoyer la réponse avec

return response; 

Mais cela ne sert à rien. Cette valeur de retour n'est pas un retour de la fonction getFriends(). C'est un retour à quelque chose à l'intérieur du moteur ajax.

Si vous voulez faire quelque chose d'utile avec la réponse FB.api(), vous devez exécuter ce code ou appeler ce code à partir de la fonction d'achèvement spécifiée dans l'appel FB.api().

Vous auriez à faire quelque chose comme ce code pseudo:

function getFriends() { 
    FB.login(function(response) { 
     if (response.session && response.perms) { 
     FB.api('/me/friends', function(response) { 
      var friends = response.data[0]; 
      var findex = friends.length 
      var randomNumber = (Math.floor(Math.random() * 10) % findex); 
      var name = friends[randomNumber].name; 
      // now continue on with whatever you want to do with the random friend info 
      // you cannot just return data from this callback, you have to actually carry 
      // out whatever you were going to do with the data here 
     }); 
     } 
    } , {perms:'publish_stream'}); 
}; 

function selectFriend(){ 
    getFriends(); 
    // the getFriends() function is asynchronous and the FB.api() call has not yet 
    // completed so we can't do anything here yet as we have to wait for the 
    // FB.api() call to finish first. 
}; 
+0

Tout d'abord, merci pour votre temps, je l'apprécie. Je vois ce que vous dites en ce qui concerne le calendrier et pourquoi il échoue en dehors de l'appel en raison de la prochaine fonction appelée avant que les données soient prêtes. Avec votre recommandation de déplacer essentiellement la logique à l'intérieur de l'appel de l'API, je suppose que le résultat escompté serait atteint, mais il me resterait le problème de le renvoyer de l'appel de l'API. Je peux trouver le nom d'un ami aléatoire (le but de l'appel), mais il sera encore fait trop vite pour être utilisé dans la boucle de remplacement. –

+0

Logiquement, ce que vous avez à faire est de faire l'appel FB et ensuite ne faites aucun de vos autres travaux pour le moment. Lorsque l'appel FB se termine et que vous avez maintenant les données FB, vous appelez une fonction à la fin de l'appel FB qui fait tous vos autres travaux parce que vous avez maintenant les données FB. Vous ne pouvez pas effectuer d'appel d'API au milieu d'une boucle et vous attendre à pouvoir utiliser le résultat dans la boucle. C'est une programmation asynchrone. C'est parfois douloureux, mais c'est comme cela que l'ajax appelle dans le navigateur. – jfriend00

+0

Très bien, j'ai marqué cette réponse comme je travaille maintenant en refactant toutes mes fonctions pour qu'elles s'exécutent juste avant ou dans l'async, selon ce qui était nécessaire. Je poste mon code ci-dessus lors d'une modification, de sorte que toute personne ayant un problème similaire peut également bénéficier de votre aide. –

Questions connexes