2010-04-13 3 views
1

J'ai un problème avec un appel ajax jQuery. Je dois attendre que l'appel soit terminé pour renvoyer une valeur. Cependant, le script semble sauter en avant et ne pas attendre que l'appel soit terminé. ma fonction retourne alors "indéfini".jQuery attendre que l'appel ajax soit terminé avant de continuer

J'ai essayé d'utiliser la méthode .ajax() et de définir la valeur de async sur false, mais cela ne fonctionnerait pas non plus.

Je pourrais obtenir ma fonction pour retourner la valeur que j'ai pu grâce à l'appel ajax?

Merci!

Voici le code:

function get_rsrce_name(){ 

    jQuery.post(

     '<?php echo admin_url('admin-ajax.php'); ?>', 

     { action :'my_action', option_rsrce : 'option_rsrce' }, 

     function(data) { 

      output = data.option_name;   

     }, 

     "json" 
    );  

    return output; 
} 
+0

similaires sur SO: http://stackoverflow.com/questions/2956261/got-stuck-in-the-asynchronous-nature-of-ajax -requests –

Répondre

2

La raison pour laquelle il ne fonctionne pas lorsque vous dites à exécuter de manière synchrone est que la « sortie » variable est uniquement définie dans le cadre de la fonction de rappel.

Il y a certainement une meilleure façon de faire ce que vous essayez de faire, mais sans plus de contexte, il sera difficile d'expliquer ce que cela pourrait être.

Je recommande la lecture sur « javascript champ variable »

1

ce que dit expansion Josh, vous avez des problèmes avec la portée de la variable « de sortie ». Vous pouvez corriger cela en déclarant la sortie en haut de votre fonction comme ceci:

var output; 
+0

Je ne pense pas que l'étendue soit le problème, et déclarer 'output' au sommet ne va pas aider. Le problème est la nature asynchrone de '$ .post'. – meagar

+0

L'OP a mentionné qu'ils ont fait un appel synchrone en définissant async: false. –

-1

par défaut de méthode .post() de jQuery à l'exécution de manière asynchrone, à savoir: la fonction post() ne s'arrête pas et attendre la réponse , il revient juste immédiatement et le reste de votre script continue. Dans ce cas, il continue à votre instruction return.

Et maintenant nous sommes dans une condition de course classique ... la requête AJAX peut-elle être complète ET exécuter le function (data) avant que le reste du script ne continue jusqu'à l'appel de retour? Étant donné que la plupart des réseaux ont des latences mesurées en millisecondes, l'appel de retour sera exécuté quelques microsecondes plus tard, très probablement pas ... l'appel de retour gagnera la course à chaque fois.

Vous devrez réorganiser votre code afin que la fonction externe appelant cette requête AJAX puisse être rappelée avec les résultats de la requête AJAX.

Une méthode simple pour le faire est de faire une fonction en deux parties:

function do_ajax(parameters, data) { 
    if (data == null) { 
     jquery.post(
      .... 
      success: function(data) { do_ajax(parameters, data); } 
     ); 
    } else { 
     ... handle response here ... 
    } 
} 

De cette façon, la fonction peut être appelée avec toutes les données dont vous avez besoin pour passer dans l'appel AJAX (parameters), et le paramètre data est initialement nul. La fonction voit que les données sont nulles, et fait l'affaire AJAX. Une fois que la réponse du serveur revient, la fonction s'appelle à nouveau, mais avec les données de réponse fournies, et l'autre partie de la fonction qui gère les données est appelée.

+0

Je ne suis pas obligé de maintenir votre code. C'est la façon la plus ridicule de le faire que je pourrais penser. Pourquoi appelleriez-vous encore do_ajax au lieu de simplement avoir une fonction qui gère la réponse? –

+0

@Keith Je suppose que cela lui semblait plus compact? Mais oui, c'est vraiment une façon de faire des choses rondes. Combiner deux fonctions en une seule, surchargée via un énorme if/else est une idée plutôt désordonnée, et encore moins l'appeler de manière récursive. – meagar

+0

@Keith. Quelle est la différence entre le demandeur ajax appelant lui-même, ou appelant une autre fonction? De toute façon, il faut appeler une fonction pour faire le traitement des données. Au moins de cette façon, la logique de demande et de traitement est conservée ensemble. Avec certaines fonctions d'encapsuleur appropriées pour ne pas encombrer le code de définitions d'URL répétitives, je trouve cela bien plus facile à maintenir que de jeter des détritus dans mon code avec les fonctions "getX" et "handleX". –

0

Je ne m'attendrais pas à ce que votre problème soit lié à des problèmes de portée, car JavaScript a une portée de fonction et non une portée de bloc. Les variables déclarées n'importe où dans une fonction sont disponibles ailleurs dans la fonction.C'est pourquoi JSLint vous dérange de les déclarer en haut: Non parce que c'est important sur le plan fonctionnel, mais parce qu'il vous rappellera que vos variables sont comme comme si elles étaient déclarées en haut, quel que soit l'endroit où vous les déclarez. Essayez cet exemple simple:

function ajax(callback) { callback(); } 
$(function() { 
    ajax(function() { x = 7; }); 
    alert(x); // x == 7 
}); 

La question est votre $.post appel est asynchrone. Vous atteignez la ligne return output; avant la ligne output = data;. Cela se produit car $.post renvoie immédiatement et permet à votre programme de continuer, alors qu'un appel AJAX potentiellement lent se produit. Lorsque l'appel AJAX est terminé, il déclenche son rappel complete.

Vous devez restructurer votre code afin que vous fassiez quelque chose avec votre valeur dans la fonction de rappel que vous passez à $.post. Vous pouvez accomplir cela en passant dans un paramètre de rappel à get_rsrce_name():

function get_rsrce_name(onComplete) { 
    $.post(url, data, function(data) { onComplete(data); }); 
}