Synchroniser une requete ajax asynchrone

cs_AlexN Messages postés 694 Date d'inscription lundi 5 décembre 2005 Statut Membre Dernière intervention 8 janvier 2014 - 26 sept. 2007 à 15:37
cs_mlwacosmos Messages postés 1 Date d'inscription vendredi 29 juin 2007 Statut Membre Dernière intervention 27 novembre 2008 - 27 nov. 2008 à 16:26
Bonjour,

Je cherche à synchroniser une requete ajax asynchrone. Et je prend une grosse suée.
Je fais appel de manière cyclique à une requete ajax en mode asynchrone.
mode cyclique parce que je relance la requete tant que la reponse ne contient pas ce qu'il faut.
mode asynchrone parce que c'est le seul mode ou abort est utilisable (et ou ça ne bloque pas le navigateur pendant les requetes)

Mais ! il faut aussi que je puisse stopper (abort) la requete si la réponse ne vient pas au bout d'un certain temps (timeout du cycle des requetes).

Je cherche à avoir une fonction du genre

while(!ready) {
   getDom(url);
}

où getDom(url) lance un cycle de requete ajax jusqu'à obtention de la reponse voulue ou que le timeout soit ecoulé.
De sorte que l'execution boucle (d'ou l'idee de synchroniser) sur ce getDom sans bloquer le reste. Suis-je clair ?

pour avoir une petite idée du contexte :

<html>
    <head>
        <title>is my datas ready ?</title>
    </head>
   
       
       
       
        stop
        <script type="text/javascript">
       
            /* XMLHttpRequest */
            var xhr = false;
            var url = "test.xml";
            var ie = false;
           
            // branch for native XMLHttpRequest object
            if(window.XMLHttpRequest && !(window.ActiveXObject)) {
                try {
                    xhr = new XMLHttpRequest();
                } catch(e) {
                    xhr = false;
                }
            // branch for IE/Windows ActiveX version
            } else if (window.ActiveXObject) {
                try {
                    xhr = new ActiveXObject("Msxml2.XMLHTTP");
                    ie = true;
                } catch(e) {
                    try {
                        xhr = new ActiveXObject("Microsoft.XMLHTTP");
                        ie = true;
                    } catch(e) {
                        xhr = false;
                    }
                }
            }
                   
            received = false;
                               
            function getContents () {                if(xhr.readyState 4 && xhr.status 200) {
                    response = xhr.responseXML;
                    if (response) {       
                        value = ie ?
                            response.getElementsByTagName("status")[0].text :
                            response.getElementsByTagName("status")[0].textContent;
                        document.getElementById("z1").value = value;
                        setTimeout("get()", 1000);
                    }
                }
            }
           
            function get () {
                if (xhr) {
                    xhr.open("GET", url, true);
                    xhr.send("");       
                }     
            }
           
            function abort() {
                xhr.abort();
                document.getElementById("z1").value='aborted';
            }
           
            xhr.onreadystatechange = getContents;
            var debut = new Date();                       
            get();
            fini = false;
           
            function f() {
                var now = new Date();
                document.getElementById("x1").value = now;
                var elapsed = now.getTime() - debut.getTime();
                document.getElementById("y1").value = elapsed;
                fini = elapsed > 5000;
                if (fini) abort();
                else setTimeout("f()", 100);
            }
            f();
           
        </script>
   
</html>

le xml (en fait la il n'y a pas ok mais not ok mais un jour il y aura ok a la place):

<?xml version="1.0" encoding="ISO-8859-1"?>
<root>
    <status>not ok</status>
</root>

si quelqu'un a une piste de reflexion, merci.

3 réponses

cs_bultez Messages postés 13615 Date d'inscription jeudi 13 février 2003 Statut Membre Dernière intervention 15 octobre 2013 30
27 sept. 2007 à 11:58
Bonjour,

    je n'ai probablement pas compris ton problème...

    setTimeout("get();", 1000); est fait sytématiquement,
    ne le faire que si la réponse n'est pas ="ok" et si le délai
       imparti pour cette réponse n'est pas atteint,
    sinon, déclencher une "fonction de fin".





<hr />                Cordialement            Bul        
0
cs_AlexN Messages postés 694 Date d'inscription lundi 5 décembre 2005 Statut Membre Dernière intervention 8 janvier 2014 19
27 sept. 2007 à 13:18
Merci pour ta suggestion bultez mais ce n'est pas ça.
En fait oui pour l'instant le setTimeout("get()", 1000); est fait systématiquement parce que c'est juste un code de test. Ce qui me précocupait ce n'était pas le contenu de la réponse. Le titre de ma question n'est pas clair non plus.
Un titre plus explicite serait plutôt : "Comment resynchroniser une requete ajax asynchrone"
et la fonction f() devrait s'appeler quelquechose comme check().

Pour l'instant ce que fait ce code :
- il lance à  intervalle régulier une requete ajax, et ce seulement quand la précédente est terminée (et il devrait aussi y avoir la condition sur "calcul fini" comme tu le fais remarquer)
- il lance "en parallèle" un compteur qui vérifie que le temps imparti n'est pas dépassé, et si celui est dépassé il stoppe la requete en cours.

Mais il ne permet pas de faire boucler temporairement l'execution sur cette portion de code

Je vais essayer d'expliquer mon problème. Je dois mettre en place un mécanisme qui :

- lance une requete ajax à intervalle régulier pour connaitre l'état d'avancement d'un calcul
- stoppe cette série de requête
  - soit lorsque la réponse contient un code disant "calcul fini"
  - soit lorsqu'un temps donné pour le cycle de requête est dépassé
- provoque un "blocage" (pas un arrêt complet mais plutôt une boucle d'attente) sur ce mécanisme (le reste du javascript ne peut pas être exécuté tant que la réponse "calcul fini" n'est pas arrivée ou que le delai d'attente de ce calcul n'est pas dépassé.

Le seul moyen pour l'instant de stopper une requete ajax est de la mettre en asynchrone.
Mais d'un autre coté, comme elle est asynchrone, le xhr.send devient non bloquant. Et la boucle d'attente n'est pas bloquante non plus.

En fouillant à droite à gauche je n'ai pas trouvé grand chose d'autre que "ca n'a pas l'air possible" à part avec des composants php (sajax) ou java (htmlunit), ce que je ne peux pas utiliser parce tout doit être réalisé du coté client.
En fait, après réflexion il semble que ce ne soit pas possible du tout. Je suis parti dans une autre direction qui serait de simuler le while par un système de timeline. Mais c'est pas gagné non plus.

Voici l'état du code quand j'ai dit stop, faut arreter :

<html>
  <head>
    <title>resync the async</title>
    <style type= "text/css">
    <!--
    .label {
      vertical-align:top;
    }
    -->
    </style>
  </head>
 
   
   
   
   
   

    <label class="label" for="readyState">Ready state : </label><textarea type="text" id="readyState" size="40" rows="30"></textarea>
    <label class="label" for="status">status : </label><textarea type="text" id="status" size="40" rows="30"></textarea>
    stop xhr
    <script type ="text/javascript">
       
      /* XMLHttpRequest */
      var xhr = false;
      var ie = false;
                       
      // branch for native XMLHttpRequest object
      if (window.XMLHttpRequest && !(window.ActiveXObject)) {
        try {
          xhr = new XMLHttpRequest();
        } catch(e) {
          xhr = false;
        }
      // branch for IE/Windows ActiveX version
      } else if (window.ActiveXObject) {
        try {
          xhr = new ActiveXObject("Msxml2.XMLHTTP");
          ie = true;
        } catch(e) {
          try {
            xhr = new ActiveXObject("Microsoft.XMLHTTP");
            ie = true;
          } catch(e) {
            xhr = false;
          }
        }
      }
     
      function getContents () {
        try {
          // Infos
          document.getElementById("readyState").value += "\n" + xhr.readyState;
          if (xhr.readyState == 4 && typeof xhr.status != 'undefined')                                 
            document.getElementById("status").value += "\n" + xhr.status;
          else                                  
            document.getElementById("status").value += "\n" + 'undefined';          if (xhr.readyState 4 && typeof xhr.status 'undefined') return;
          // Contents          if (xhr.readyState 4 && (xhr.status 200 || xhr.status == 0)) {
            response = xhr.responseXML;
            if (response) {                             
              document.getElementById("z1").value = (ie ?                        
                response.getElementsByTagName("status")[0].text :                         
                response.getElementsByTagName("status")[0].textContent) + " " + times++;
              getTimer = setTimeout("get(url)", 1000);
            }
          }
              } catch (e) {
                  if (typeof console != 'undefined') console.log(e);             
              }
      }
                       
      function get(url) {
              //try {
          if (xhr) {
            xhr.open("GET", url, true);
            xhr.send("");
          }            
              //} catch (e) {}
      }
     
      function abort() {
        if (xhr) {
          xhr.abort();
          document.getElementById("message").value = 'aborted';
        }
              if (checkTimer) clearTimeout(checkTimer);
              if (getTimer) clearTimeout(getTimer);
      }
                       
      function check() {
        var now = new Date();
        document.getElementById("x1").value = now;
        var elapsed = now.getTime() - start.getTime();
        document.getElementById("y1").value = elapsed;
        timeover = elapsed > 5000;
        if (timeover) abort();
        else checkTimer = setTimeout("check()", 100);
      }
     
      if (xhr) xhr.onreadystatechange = getContents;
      document.getElementById('readyState').value = "";
      document.getElementById('status').value = "";
           
      var start = new Date();
      var checkTimer, getTimer;
      var timeover = false;
      url = "test.xml";
      var send = false;
      var times = 1;
     
      function getStatus(url, send) {
           
        if (!send) {
          send = false;
          get(url);                               
          check();
        }
              /*
        if (!timeover) {
          if (xhr.readyState == 4) {
            send = true;
            getTimer = setTimeout("get(url)", 1000);   
                    return true;
          } else
                     checkTimer = setTimeout("getStatus(url, send)", 1000);
            return false;
        }
              */
      }
             
      //get(url);                               
      //check();
      getStatus(url, send);
      //while (!getStatus(url, send));
                       
    </script>
 
</html>

Je jette l'éponge pour cette voie...
Enfin merci.
0
cs_mlwacosmos Messages postés 1 Date d'inscription vendredi 29 juin 2007 Statut Membre Dernière intervention 27 novembre 2008
27 nov. 2008 à 16:26
Bonjour,
La question est ancienne mais je peux fournir une réponse et ça peut toujours aider.

Pour les puristes une requête ajax est forcément asynchrone et il est interdit de lancer des requêtes synchrones si bien qu'un navigateur comme firefox ne l'accepte pas facilement.
Néanmoins c'est possible en changer le paramètre true en false.
Sous ie pas de soucis, mais sous firefox il faudra recopier apres le request.send les différentes bifurcations que l'on fait habituellement quand on reçoit la réponse du serveur.

Un petit exemple pour firefox? ok

request.onreadystatechange = function () {
   if(request.readyState == 4) {
      if(request.status == 200) {
         //ce que je fais
      }
   }
}
request.send(null);
if(not ie et requete est synchrone(à savoir false pour le paramètre) {
   //ce que je fais
}
 Le problème avec firefox c'est que l'on ne vérifie pas le code de retour du serveur.
0
Rejoignez-nous