Récupérer une valeur via XHR dans une variable JavaScript

Répondre


Cette question est un moyen d’empêcher des soumissions automatisées de formulaires par des robots.
Smileys
:D :) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen: =D> #-o =P~ :^o :non: :priere: 8-|
Voir plus de smileys
  Revue du sujet
 

  Étendre la vue Revue du sujet : Récupérer une valeur via XHR dans une variable JavaScript

par Cyrano » 04 mars 2006, 22:28

Mouais, ben désolé Naholyr, mais je ne comprends pas grand chose à ton code et sans commentaires, ça aide pas des masses. Je me fous également un peu de la date ou de savoir sur quel fuseau horaire je suis, je veux juste faire un truc simple qui me synchronise l'heure/minute/seconde : point barre, rien de plus.

Enfin bon, tant pis, laisse tomber, je mets le sujet en délestage, j'ai l'impression que tout ce qui touche AJAX va encore me poser quelques difficultés...

par Cyrano » 04 mars 2006, 16:58

Merci infiniment Naholyr, je vais immédiatement me plonger dans ton code, ça m'intéresse bougrement :)

par naholyr » 04 mars 2006, 16:43

En fait le plus simple c'est de fonctionner comme un serveur NTP :
- toutes les 30 secondes, demander la différence entre l'heure serveur et l'heure locale.
- chaque seconde récupérer l'heure locale et ajouter la différence.

De cette façon les variations ne peuvent être qu'infimes.

Tiens je t'ai préparé un exemple : time.php
<?php echo @$_GET['time'] ? time()*1000-$_GET['time'] : 0; ?>
time.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Tic ! Tac !</title>
<style type="text/css">
/*<![CDATA[*/
#logger { width: 800px; height: 400px; border: 2px solid #ccc; padding: 5px; margin: 0; font-family: courier; font-size: 10px; overflow: auto; }
#clock { width: 800px; height: 25px; font-size: 20px; padding: 5px; margin: 0; border: 2px solid #ddd; background: #eee; color: #333 }
/*]]>*/
</style> 
<script type="text/javascript">

function XHR() {
    var conn;
	try {
		conn = new XMLHttpRequest();
	}
	catch (error) {
		if (debug) { alert('Erreur lors de la tentative de crйation de l\'objet \nnew XMLHttpRequest()\n\n' + error); }
		try {
			conn = new ActiveXObject("Microsoft.XMLHTTP");
		}
		catch (error) {
			if (debug) { alert('Erreur lors de la tentative de crйation de l\'objet \nnew ActiveXObject("Microsoft.XMLHTTP")\n\n' + error); }
			try {
				conn = new ActiveXObject("Msxml2.XMLHTTP");
			}
			catch (error) {
				if (debug) { alert('Erreur lors de la tentative de crйation de l\'objet \nnew ActiveXObject("Msxml2.XMLHTTP")\n\n' + error); }
				conn = false;
			}
		}
	}
    return conn;
}

window.globalObjects = new Array();
function objectGlobalID(obj) {
    // generate random ID to have a public function pointer to this.tick 
    var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz"; 
    while (true) { 
        var randomstring = "";
        for (var i=0; i<5; i++) { 
            var rnum = Math.floor(Math.random() * chars.length); 
            randomstring += chars.substring(rnum,rnum+1); 
        }
        randomstring = "_"+randomstring;
        if (!window.globalObjects[randomstring]) { 
            window.globalObjects[randomstring] = obj;
            return randomstring;
        } 
    }
}

function Logger(layerID) {
    this.layerID = layerID;
    this.paused = false;
    this.str = "";
    this.log = function(line) {
        var str = (new Date()).getTime()+" : "+line+"<br />";
        if (this.paused) {
            this.str = str+this.str;
        }
        else {
            str += this.str;
            var d = document.getElementById(this.layerID);
            if (d)
                d.innerHTML = str+d.innerHTML;
            this.str = "";
        }
    }
}

function ServerClock(layerID, serverPage) {
    this.layerID = null;
    this.serverPage = null;
    this.id = objectGlobalID(this);
    this.xhr = XHR();
    this.date = null;
    this.logger = null;
    this.delay = 0;
    if (layerID)
        this.attachToLayer(layerID);
    if (serverPage)
        this.attachToServer(serverPage);
}
ServerClock.prototype.activateDebugging = function(layerID) {
    this.logger = new Logger(layerID);
}
ServerClock.prototype.debug = function(line) {
    if (this.logger)
        this.logger.log(line);
}
ServerClock.prototype.start = function() {
    this.debug("start()");
    this.date = new Date();
    if (this.serverPage) {
        this.getDelayFromServer();
        setInterval("window.globalObjects['"+this.id+"'].getDelayFromServer()", 30000);
    }
    this.display();
    setInterval("window.globalObjects['"+this.id+"'].tick()", 1000);
}
ServerClock.prototype.attachToLayer = function(layerID) {
    this.layerID = layerID;
}
ServerClock.prototype.attachToServer = function(serverPage) {
    this.serverPage = serverPage;
}
ServerClock.prototype.getDelayFromServer = function() {
    this.debug("<b>updateFromServer : date = "+this.date+"</b>");
    if (!this.xhr) {
        this.debug("NO XHR !");
        return false;
    }
    var my = this;
    my.xhr.open("GET", this.serverPage+"?time="+this.date.getTime());
    my.xhr.onreadystatechange = function() {
        if (my.xhr.readyState == 4 && my.xhr.status == 200) {
            my.debug("<b>updateFromServer : got delay = "+my.xhr.responseText+"</b>");
            my.delay = Math.round(my.xhr.responseText);
        }
    }
    my.xhr.send("");
}
ServerClock.prototype.addDelay = function(ms) {
    var oldDate = ""+this.date;
    this.date.setTime(this.date.getTime()+ms);
    this.debug("addDelay() : "+oldDate+" + "+ms+"ms = "+this.date);
}
ServerClock.prototype.display = function() {
    if (this.layerID) {
        var d = document.getElementById(this.layerID);
        if (d)
            d.innerHTML = this.date;
    }
}
ServerClock.prototype.tick = function() {
    this.debug("tick()");
    this.date = new Date();
    this.addDelay(this.delay);
    this.display();
}

var c = new ServerClock("clock", "time.php");
c.activateDebugging("logger");

</script>
</head>
<body onload="c.start()">
<div id="clock"></div>
<p><a href="#" onclick="c.logger.paused=!c.logger.paused; return false">Activer/Dйsactiver le logger</a></p>
<div id="logger"></div>
</body>
</html>

par Cyrano » 04 mars 2006, 16:01

Ben j'ai même essayé un truc : récupérer un getTime() en début de script, un autre en fin de script et de faire ensuite :
var temporisation = benchFin - benchDebut;
setTimeout('mafonction()', temporisation);
Mais même au millième je n'ai as de différence due au temps d'exécution.

Là où j'ai des difficultés, c'est pour comprendre pourquoi réinitialiser des variables dans un objet XHR ne dure pas. En plus clair : toutes les x secondes, je recale mon horloge : pour ce faire, je modifie la valeur de mon paramètre envoyé lors de l'appel de ma fonction horloge en la synchronisant avec le retour XHR. Sauf qu'à la seconde suivante, on revient à la valeur précédente avec un décalage supplémentaire qui n'apparaît même pas dans le bench. Décidément, je n'y capte pas grand chose si ce n'est que une heure avec un recalage toutes les 5 secondes, je prends plus de deux minutes de retard. Ma calvitie était déjà bien avancée, il est à craindre que ça ne s'aggrave. (Ha la calvitie quelle vie c'est !)

Bon, je vais jeter un coup d'oeil sur les liens de (X:?:) Hubert Roksor :-k

par naholyr » 04 mars 2006, 15:06

Normal, pour peu que ton serveur mette 2 secondes à afficher la page demandée par l'objet XHR, tu te retrouves avec 2 secondes de retard...

Les appels asynchrones c'est sympa, mais il faut tenir compte du lag (Un des liens dans la signature d'Hubert t'en parlera mieux que moi ;)).

Si ce n'est pas une question de lag, prends garde également à la fonction setTimeout, qui n'est pas la même chose que setInterval.

Un exemple parlant :

Code : Tout sélectionner

function a() { // un traitement qui dure 3 secondes setTimeout("a()", 1000); // on exécute a() toutes les secondes }
Le temps d'exécution de la fonction est pris en compte, puisque setTimeout est une instruction dans le corps de la fonction. et a() au lieu d'être exécutée à chaque seconde, n'est en réalité exécutée que toutes les 1+X secondes, où X est le temps d'exécution du corps de la fonction.

Un petit ralentissement sur la machine du client te pourrira ton horloge.

setInterval() y sera beaucoup moins sensible, puis qu'il crée une tache parallèle, et ne prend donc pas en compte le temps d'exécution de la fonction. Ce qui peut amener des résultats très etranges si le temps d'exécution de ta fonction est supérieur à l'intervalle : il faut prendre en compte de la même façon les ralentissements du client (setInterval est à setTimeout ce que l'asynchrone est au synchrone dans Ajax).

Beaucoup de paramètres à prévoir ;)

par Cyrano » 04 mars 2006, 09:51

Bon, laissez tomber, j'ai résolu la question : en fait, j'ai transféré le contenu de ma fonction go() directement dans une alternative de la fonction horloge() et ça fonctionne.

En revanche, appliquer ce système à une horloge ne semble pas avoir une efficacité extraordinaire, il y a un décallage qui augmente rapidement entre l'heure serveur et l'heure affichée, j'affiche deux secondes de retard en moins de trois minutes, pas terrible, je vais essayer de trouver une autre méthode.

Récupérer une valeur via XHR dans une variable JavaScript

par Cyrano » 04 mars 2006, 00:39

Bonjour,
je bataille depuis quelques heures avec AJAX et les objets XHR, on se distrait comme on peut :P

Mon problème est le suivant. Je crée une petite horloge que j'affiche dans un coin de page web. Cette horloge est basée sur l'heure du serveur et tourne grâce à une fonction JavaScript et un setTimeout. À ce stade, ça fonctionne très bien. Mais là où ça se complique, c'est que je veux périodiquement synchroniser mon horloge avec l'heure du serveur sans recharger toute ma page bien entendu.

Au premier chargement de ma page, je récupère l'heure en PHP sous la forme du nombre de secondes (pour les besoins du test, ça me donne moins à attendre pour vérifier le fonctionnement) que ça représente avec ce petit bout de code :
<?php
function  hc()
{
    $h = date("H");
    $m = date("i");
    $s = date("s");
    $heure = ($h * 60 * 60) + ($m * 60) + $s;
    return $heure;
}
?>
Mais comme je veux synchroniser par exemple toutes les trente secondes sans recharger toute la page, je dois appeler ce code via un objet XHR et affecter la valeur de retour à une variable JavaScript qui va recaler mon script d'horloge.

La partie JavaScript qui ne fonctionne pas :
/**
 * Méthode qui sera appelée toutes les x minutes/secondes selon un paramètre de timeout
 * dans la fonction horloge.
 */
function go()
{
    getXhr();
	//alert(xhr);
    /* On défini ce qu'on va faire quand on aura la réponse */
    xhr.onreadystatechange = function()
    {
        /* On ne fait quelque chose que si on a tout reçu et que le serveur est ok */
        if(xhr.readyState == 4)
        {
		    alert(xhr.responseText);
			if(xhr.status == 200)
            {
			    var secondes = xhr.responseText;
			}
        }
		else
		{
		    alert('Il y a quelque chose de pourri dans ce code !\n'+ xhr.readyState);
		}
    }
    xhr.open("GET", xhr_secondes, true);
    xhr.send(null);
}


/**
 * Fonction de rotation de l'horloge
 * La fonction reçoit en paramètre l'heure courante au format HH:mn:sc
 */
function horloge(totalSecondes)
{
    /* Mise à jour toutes les trente secondes */
	go();
	var t = secondes;
	//alert(t);
	totalSecondes = ((totalSecondes % 30) != 0) ? totalSecondes : ((t == 'undefined') ? totalSecondes : t);
Dans le début de la fonction horloge, mon "alert(t)"; me renvoie systématiquement "undefined".
Dans ma fonction go(), xhr.readyState me retourne 1 ou 2, parfois 3 mais jamais 4.

En résumé, ma question est la suivante : comment récupérer la valeur de retour de ma fonction PHP hc() pour l'affecter à ma variable JavaScript t dans horloge() avec la fonction go() ?

Si quelqu'un a une piste à m'indiquer, je la suivrai volontiers, merci d'avance.