2009-04-16 8 views
197

J'ai une fonction côté serveur qui nécessite une connexion. Si l'utilisateur est connecté, la fonction retournera 1 en cas de succès. Sinon, la fonction retournera la page de connexion.Comment faire pour que jQuery attende qu'un appel Ajax se termine avant qu'il ne retourne?

Je souhaite appeler la fonction en utilisant Ajax et jQuery. Ce que je fais est soumettre la demande avec un lien ordinaire, avec une fonction de clic appliquée sur elle. Si l'utilisateur n'est pas connecté ou si la fonction échoue, je souhaite que l'appel Ajax renvoie true, afin que le href se déclenche. Toutefois, lorsque j'utilise le code suivant, la fonction se ferme avant que l'appel Ajax soit terminé.

Comment puis-je rediriger l'utilisateur vers la page de connexion?

$(".my_link").click(
    function(){ 
    $.ajax({ 
     url: $(this).attr('href'), 
     type: 'GET', 
     cache: false, 
     timeout: 30000, 
     error: function(){ 
      return true; 
     }, 
     success: function(msg){ 
      if (parseFloat(msg)){ 
       return false; 
      } else { 
       return true; 
      } 
     } 
    }); 
}); 
+1

Peut-être un ancien thread, mais comme @kofifus souligne le réglage d'un sync to false est un mauvais design et "aucun timeout, etc. ne sera traité". Peut-être essayer cette solution simplifiée - https: // stackoverflow.com/a/11576418/6937841 – Shan

Répondre

295

Si vous ne voulez pas la fonction $.ajax() pour revenir immédiatement, réglez l'option async-false:

$(".my_link").click(
    function(){ 
    $.ajax({ 
     url: $(this).attr('href'), 
     type: 'GET', 
     async: false, 
     cache: false, 
     timeout: 30000, 
     error: function(){ 
      return true; 
     }, 
     success: function(msg){ 
      if (parseFloat(msg)){ 
       return false; 
      } else { 
       return true; 
      } 
     } 
    }); 
}); 

Mais, je constate que ce serait contraire au point d'AJAX. En outre, vous devez gérer la réponse dans les fonctions error et success. Ces fonctions ne seront appelées que lorsque la réponse sera reçue du serveur.

+1

Vous voulez dire faux :) Je suppose? – veggerby

+0

Hah! Oui merci. – cgp

+9

Passer à côté des bonnes pratiques, à mon avis, n'est pas un jugement, et c'est la marque de certaines des meilleures réponses ici sur StackOverflow. – semperos

27

L'objet XMLHttpRequest sous-jacent (utilisé par jQuery pour effectuer la requête) prend en charge la propriété asynchrone . Réglez-le sur false. Comme

async: false 
9

Je pense que les choses seraient plus faciles si vous codez votre fonction success pour charger la page appropriée au lieu de retourner true ou false.

Par exemple au lieu de retourner true que vous pourriez faire:

window.location="appropriate page"; 

De cette façon, lorsque la fonction de la réussite est la page est redirigé.

30

Je n'utilise pas $.ajax mais les fonctions $.post et $.get, donc si je dois attendre la réponse, j'utilise ceci:

$.ajaxSetup({async: false}); 
$.get("..."); 
+0

Ceci fonctionne pour $ .getJSON() aussi ... ce qui est logique –

17

Au lieu de définir async false qui est la conception généralement mauvais, vous peut vouloir envisager de bloquer l'interface utilisateur pendant que l'opération est en attente.

Ceci peut être réalisé bien avec jQuery promet comme suit:

// same as $.ajax but settings can have a maskUI property 
// if settings.maskUI==true, the UI will be blocked while ajax in progress 
// if settings.maskUI is other than true, it's value will be used as the color value while bloking (i.e settings.maskUI='rgba(176,176,176,0.7)' 
// in addition an hourglass is displayed while ajax in progress 
function ajaxMaskUI(settings) { 
    function maskPageOn(color) { // color can be ie. 'rgba(176,176,176,0.7)' or 'transparent' 
     var div = $('#maskPageDiv'); 
     if (div.length === 0) { 
      $(document.body).append('<div id="maskPageDiv" style="position:fixed;width:100%;height:100%;left:0;top:0;display:none"></div>'); // create it 
      div = $('#maskPageDiv'); 
     } 
     if (div.length !== 0) { 
      div[0].style.zIndex = 2147483647; 
      div[0].style.backgroundColor=color; 
      div[0].style.display = 'inline'; 
     } 
    } 
    function maskPageOff() { 
     var div = $('#maskPageDiv'); 
     if (div.length !== 0) { 
      div[0].style.display = 'none'; 
      div[0].style.zIndex = 'auto'; 
     } 
    } 
    function hourglassOn() { 
     if ($('style:contains("html.hourGlass")').length < 1) $('<style>').text('html.hourGlass, html.hourGlass * { cursor: wait !important; }').appendTo('head'); 
     $('html').addClass('hourGlass'); 
    } 
    function hourglassOff() { 
     $('html').removeClass('hourGlass'); 
    } 

    if (settings.maskUI===true) settings.maskUI='transparent'; 

    if (!!settings.maskUI) { 
     maskPageOn(settings.maskUI); 
     hourglassOn(); 
    } 

    var dfd = new $.Deferred(); 
    $.ajax(settings) 
     .fail(function(jqXHR, textStatus, errorThrown) { 
      if (!!settings.maskUI) { 
       maskPageOff(); 
       hourglassOff(); 
      } 
      dfd.reject(jqXHR, textStatus, errorThrown); 
     }).done(function(data, textStatus, jqXHR) { 
      if (!!settings.maskUI) { 
       maskPageOff(); 
       hourglassOff(); 
      } 
      dfd.resolve(data, textStatus, jqXHR); 
     }); 

    return dfd.promise(); 
} 

avec cela, vous pouvez faire:

ajaxMaskUI({ 
    url: url, 
    maskUI: true // or try for example 'rgba(176,176,176,0.7)' 
}).fail(function (jqXHR, textStatus, errorThrown) { 
    console.log('error ' + textStatus); 
}).done(function (data, textStatus, jqXHR) { 
    console.log('success ' + JSON.stringify(data)); 
}); 

Et l'interface utilisateur permet de bloquer jusqu'à ce que la commande retourne ajax

Voir jsfiddle

+0

Ne pas mettre async à false faire exactement la même chose sauf dans une seule ligne de code? – Vincent

+3

pas du tout.Async à faux faire la demande async - c'est l'arrêt du traitement jusqu'à ce qu'il retourne ce qui est généralement une mauvaise pratique, par exemple non e les évents, les autres requêtes ajax, les délais d'attente, etc. seront traités. Vous pouvez également modifier le code ci-dessus pour ne bloquer qu'une partie de l'interface utilisateur pendant le traitement de votre ajax (c'est-à-dire la partie qui sera affectée) – kofifus

Questions connexes