2011-07-27 3 views
326

Cette question est posée plusieurs fois dans SO. Mais je ne peux toujours pas avoir de trucs.Comment renvoyer la valeur d'une fonction de rappel asynchrone?

Je souhaite obtenir une valeur de rappel. Regardez le script ci-dessous pour des éclaircissements.

function foo(address){ 

     // google map stuff 
     geocoder.geocode({ 'address': address}, function(results, status) { 
      results[0].geometry.location; // I want to return this value 
     }) 

    } 
    foo(); //result should be results[0].geometry.location; value 

Si j'essaie de retourner cette valeur, je deviens simplement "indéfini". J'ai suivi quelques idées de SO, mais échoue toujours.

Ce sont:

function foo(address){ 
    var returnvalue;  
    geocoder.geocode({ 'address': address}, function(results, status) { 
     returnvalue = results[0].geometry.location; 
    }) 
    return returnvalue; 
} 
foo(); //still undefined 
+11

Toute personne qui a obtenu ici [** S'il vous plaît lire cette première question **] (http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call). Il explique comment s'attaquer efficacement à ce problème. –

+0

** [Pourquoi ma variable est-elle inchangée après que je l'ai modifiée dans une fonction? - Référence de code asynchrone] (http://stackoverflow.com/questions/23667086/why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron) ** fournit également une explication plus générale et détaillée du problème. –

+0

Utilisez Q, ou l'une de ses variantes, comme la bibliothèque $ q fournie avec angularJs. Et ne jamais regarder en arrière. Les fonctions asynchrones retournent immédiatement indéfini. Donc, ne perdez jamais votre temps à essayer de faire des choses sur indéfini. Ne jamais utiliser le mot-clé 'return' dans vos fonctions asynchrones, comme vous le faites habituellement. Utilisez plutôt des promesses différées. deferred.resolve (STUFF que vous voulez faire), alors vous pouvez revenir plus tard simplement que, «retour deferred.promise; '. :) – ISONecroMAn

Répondre

336

Ceci est impossible car vous ne pouvez pas retourner d'un appel asynchrone dans une méthode synchrone.

Dans ce cas, vous devez passer un rappel à foo qui recevra la valeur de retour

function foo(address, fn){ 
    geocoder.geocode({ 'address': address}, function(results, status) { 
    fn(results[0].geometry.location); 
    }); 
} 

foo("address", function(location){ 
    alert(location); // this is where you get the return value 
}); 

La chose est, si un appel de fonction intérieure est asynchrone, tous les de l'emballage 'fonctions cette appel doit également être asynchrone afin de «renvoyer» une réponse.

Si vous avez beaucoup de rappels, vous pouvez envisager de franchir le pas et d'utiliser un promise library like Q.

+3

:) Ce n'est pas fort, c'est juste comme ça. Dès que vous utilisez une méthode asynchrone pour transmettre des données, la chaîne de fonctions entière devient asynchrone. –

+0

Si la chaîne de fonctions asynchrones manipule un objet, disons un objet 'graphique'. Y at-il de toute façon je peux obtenir une référence à cet objet pour appeler quelque chose comme mise à jour() là-dessus? – user2483724

+2

Upvote pour finalement faire de ce sens. –

18

Il n'a pas de sens pour renvoyer des valeurs d'un rappel. Au lieu de cela, faites le travail "foo()" que vous voulez faire à l'intérieur votre rappel.

Les rappels asynchrones sont invoqués par le navigateur ou par un cadre tel que la bibliothèque de géocodage Google lorsque des événements se produisent. Il n'y a pas de place pour les valeurs renvoyées. Une fonction de rappel peut renvoyer une valeur, en d'autres termes, mais le code qui appelle la fonction ne fera pas attention à la valeur de retour.

14

Si vous arrive d'utiliser jQuery, vous pouvez donner à ce coup: http://api.jquery.com/category/deferred-object/

Il vous permet de différer l'exécution de votre fonction de rappel jusqu'à ce que la demande ajax (ou toute opération asynchrone) est terminée . Cela peut également être utilisé pour rappeler une fois que plusieurs requêtes ajax sont terminées.

Questions connexes