IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

AJAX Discussion :

[AJAX - PHP] Lancer des requêtes dans une boucle


Sujet :

AJAX

  1. #1
    Membre averti
    Avatar de Psycadi
    Homme Profil pro
    Chef de projet - Expert en message box
    Inscrit en
    Juillet 2003
    Messages
    147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet - Expert en message box

    Informations forums :
    Inscription : Juillet 2003
    Messages : 147
    Points : 364
    Points
    364
    Par défaut [AJAX - PHP] Lancer des requêtes dans une boucle
    Bonjour,

    J'ai un petit problème avec une fonction AJAX.

    J'ai un formulaire avec plein de case à cocher (une sorte de liste) et je veux lancer un traitement à chaque case cochée. Le problème est que le traitement peut être très long si je lance tout d'un coup dans un script php (environ 1 seconde de traitement par case cochée * 1000 cases environ).

    Donc, j'ai décidé de faire de l'ajax pour lancer 1000 fois un script.

    Le problème c'est que ça marche très bien sur FF mais pas du tout sur IE6 (pb sur l'état d'avancement).

    Voici en gros ma fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
     
    var xhr_object = null;
     
    if(window.XMLHttpRequest) // Firefox 
    	xhr_object = new XMLHttpRequest(); 
    else if(window.ActiveXObject) // Internet Explorer 
    	xhr_object = new ActiveXObject("Microsoft.XMLHTTP"); 
    else { // XMLHttpRequest non supporté par le navigateur 
    	alert("Votre navigateur ne supporte pas cette fonctionnalité du site."); 
    	return; 
    }
     
    for (var i=0;i<checkboxes.length;i++)
    {
    	if(checkboxes[i].type == 'checkbox')
    	{
    		if (checkboxes[i].checked == true)
    		{
    			no_cache = Math.random();
    			//récupérer les valeurs
    			var sendData = "idRub=" + checkboxes[i].value + "&idDest=" + idDest + "&idSource=" + idSource + "&nocache=" +no_cache; // défini plus haut dans le script / sans intérêt pour mon pb
    			xhr_object.open('post', 'duplicate.php',true);
     
    			xhr_object.onreadystatechange = function() { 
    				if(xhr_object.readyState == 4)
    				{		
    					if(xhr_object.responseText == 0)
    					{
    						iOk++;
    						lblOk.innerHTML = iOk;
    					}
    					else
    					{
    						iErreur++;
    						lblErreur.innerHTML = iErreur;
    					}
    				}
    			}
     
    			xhr_object.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    			xhr_object.send(sendData);
    		}
    	}
    }
    Mon gros problème, c'est qu'il lance bien tous les script mais qu'il n'attend pas les réponse et du coup, il ne fait rien du tout (sauf la première).

    Pouvez-vous m'aider?

    Je sais vraiment pas quoi faire là.

    Merci d'avance

  2. #2
    Membre expérimenté
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    1 132
    Détails du profil
    Informations personnelles :
    Âge : 52
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 132
    Points : 1 418
    Points
    1 418
    Par défaut
    Bonjour,

    Citation Envoyé par JaCaDi Voir le message
    (environ 1 seconde de traitement par case cochée * 1000 cases environ).

    Donc, j'ai décidé de faire de l'ajax pour lancer 1000 fois un script.
    Hum... Qu'est-ce qui est long exactement ?
    Si c'est le traitement PHP, lancer 1000 fois un appel ajax risque de prendre encore plus de temps car tu vas faire 1000 appels http au lieu de 1.


    En ce qui concerne ton algorithme, il faudrait plutôt faire une sorte de boucle "repeat until" qui va provoquer l'appel ajax suivant et s'arrêter à la dernière "case à cocher".
    C'est à dire que c'est la callback (readyStateChange avec status = 4) qui devrait déclencher l'envoi suivant si nécessaire.

    devyan

  3. #3
    Membre averti
    Avatar de Psycadi
    Homme Profil pro
    Chef de projet - Expert en message box
    Inscrit en
    Juillet 2003
    Messages
    147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet - Expert en message box

    Informations forums :
    Inscription : Juillet 2003
    Messages : 147
    Points : 364
    Points
    364
    Par défaut
    En fait, le traitement fait par le script php peut être très long (il balance 200 requêtes et je ne peux pas l'améliorer sans refaire toute la base).

    Donc, je ne fais pas ça pour accélérer le traitement mais juste pour qu'il passe coté serveur car un script php est stoppé au bout de 30 sec chez l'hébergeur. La solution du script AJAX qui envoi plein de petit script php me permet donc de passer par dessus ce problème.

    En fait, je comptais faire un boucle avec deux variables (iEnCours et iTodo) et les comparer pour savoir si je peux lancer la requête suivante. Et dans ma fonction de callback, incrémenter la iEnCours pour dire qu'on peux passer à la suivante.

    Mais je galère un peu.

  4. #4
    Expert éminent sénior

    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    13 474
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2007
    Messages : 13 474
    Points : 36 571
    Points
    36 571
    Par défaut
    Bonjour,
    Citation Envoyé par JaCaDi Voir le message
    En fait, je comptais faire un boucle avec deux variables (iEnCours et iTodo) et les comparer pour savoir si je peux lancer la requête suivante. Et dans ma fonction de callback, incrémenter la iEnCours pour dire qu'on peux passer à la suivante.
    Cette solution serait beaucoup plus simple (et logique)
    Citation Envoyé par devyan Voir le message
    c'est la callback (readyStateChange avec status = 4) qui devrait déclencher l'envoi suivant
    A+

  5. #5
    Rédacteur

    Avatar de Bovino
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juin 2008
    Messages
    23 647
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 23 647
    Points : 91 220
    Points
    91 220
    Billets dans le blog
    20
    Par défaut
    c'est qu'il lance bien tous les script mais qu'il n'attend pas les réponse
    Oui, c'est un peu le principe d'une requête asynchrone, tu ne rencontreras plus ce souci en lançant des requêtes synchrones.
    De plus, en asynchrone, le nombre de requêtes simultanées est limité (en général à 3), mais dans ton cas, vu que ta variable contenant l'objet xhr est globale, il y a probablement des conflits.

    Citation Envoyé par devyan
    Si c'est le traitement PHP, lancer 1000 fois un appel ajax risque de prendre encore plus de temps car tu vas faire 1000 appels http au lieu de 1.
    Tu devrais prendre en compte cet argument... multiplier par 1000 le nombre de requêtes HTTP ne fait pas bon ménage avec les performances.

    car un script php est stoppé au bout de 30 sec chez l'hébergeur.
    J'ai l'impression que l'essentiel du problème vient de là : si tu n'as pas la main sur la config du serveur, c'est que tu es probablement sur un hébergement mutualisé, qui n'est pas, d'après ce que tu décris, adapté à tes besoins.
    Et si c'est bien un mutualisé, multiplier par 1000 le nombre de requêtes HTTP t'expose à te faire virer.

    Tu ferais largement mieux de revoir ton hébergement et de l'adapter à tes besoins.

  6. #6
    Membre averti
    Avatar de Psycadi
    Homme Profil pro
    Chef de projet - Expert en message box
    Inscrit en
    Juillet 2003
    Messages
    147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet - Expert en message box

    Informations forums :
    Inscription : Juillet 2003
    Messages : 147
    Points : 364
    Points
    364
    Par défaut
    Je suis tout à fait d'accord avec toi Bovino. Il me faudrait un serveur dédié et non pas mutualisé mais, à vrai dire, je n'ai pas trop le choix. Il faut que je fasse avec.

    J'avais bien pigé le coup de l'asynchrone mais dans mon cas, il lance tout (ok) mais il ne fait que le premier callback car ensuite il sort de la fonction JS (logique aussi dans un sens mais.... grmffff)

    Bref, j'étais focalisé sur le problème de la durée du script php que je voulais réduire que je n'ai pas pensé aux nombres de requêtes HTTP qui seront envoyées en passant par AJAX.

    Du coup, j'ai l'impression de repartir au point de départ. Une fonction php de plus de 20 minutes (si on coche les 1000 cases) et bien peu de solution.

    Envoyé par devyan
    c'est la callback (readyStateChange avec status = 4) qui devrait déclencher l'envoi suivant
    J'aimerais bien tester cette solution mais... je ne vois pas du tout quoi mettre dans cette saleté de callback, même si je suis d'accord sur le fait que ce soit beaucoup plus propre.

    Le temps de traitement n'est pas vraiment un problème du moment que ça marche.

  7. #7
    Expert éminent sénior

    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    13 474
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2007
    Messages : 13 474
    Points : 36 571
    Points
    36 571
    Par défaut
    Citation Envoyé par JaCaDi Voir le message
    je ne vois pas du tout quoi mettre dans cette saleté de callback,
    ça pourrait ressembler à ça (ce qui ne remet pas en cause les warning de Bovino)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    var tabChkbx = new Array();
    var indChkbx = 0;
     
    function AlimtabChkbx() {
    	for (var i=0;i<checkboxes.length;i++)
    	{
    		if(checkboxes[i].type == 'checkbox')
    		{
    			if (checkboxes[i].checked == true)
    				tabChkbx.push(checkboxes[i].value);   // alimente la liste des paramètres des appels successifs
    		}
    	}
    }
     
    function DoIt(ind) {
    	var xhr_obj = GetXHR();
    	no_cache = Math.random();
    	//récupérer les valeurs
    	var sendData = "idRub=" + tabChkbx[ind] + "&idDest=" + idDest + "&idSource=" + idSource + "&nocache=" +no_cache; // défini plus haut dans le script / sans intérêt pour mon pb
    	xhr_object.open('post', 'duplicate.php',true);
     
    	xhr_object.onreadystatechange = function() { 
    		if(xhr_object.readyState == 4)
    		{		
    			if(xhr_object.responseText == 0)
    			{
    				iOk++;
    				lblOk.innerHTML = iOk;
    				DoIt(indChkbx++);			//  après traitement de la réponse, lance la requete suivante
    			}
    			else
    			{
    				iErreur++;
    				lblErreur.innerHTML = iErreur;
    			}
    		}
    	}
     
    	xhr_object.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    	xhr_object.send(sendData);
    }
     
    function GetXHR() {
    	var xhr_object = null;
     
    	if(window.XMLHttpRequest) // Firefox 
    		xhr_object = new XMLHttpRequest(); 
    	else if(window.ActiveXObject) // Internet Explorer 
    		xhr_object = new ActiveXObject("Microsoft.XMLHTTP"); 
    	else { // XMLHttpRequest non supporté par le navigateur 
    		alert("Votre navigateur ne supporte pas cette fonctionnalité du site."); 
    		return; 
    	}
     
    	return xhr_object;
    }
     
    // Lance le traitement
    AlimtabChkbx();
    DoIt(indChkbx);
    EDIT : par contre, j'ai un doute sur ton test
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if(xhr_object.responseText == 0)


    A+

  8. #8
    Membre averti
    Avatar de Psycadi
    Homme Profil pro
    Chef de projet - Expert en message box
    Inscrit en
    Juillet 2003
    Messages
    147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet - Expert en message box

    Informations forums :
    Inscription : Juillet 2003
    Messages : 147
    Points : 364
    Points
    364
    Par défaut
    Citation Envoyé par E.Bzz Voir le message
    EDIT : par contre, j'ai un doute sur ton test
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if(xhr_object.responseText == 0)
    En fait dans mon script php, je fais un echo 0 si c'est bon et un echo 'ERREUR' si ce n'est pas bon.

    Ce n'est peut-être pas une bonne idée.

    Merci de vos aides, je vais essayer d'appliquer cela.

  9. #9
    Expert éminent sénior

    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    13 474
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2007
    Messages : 13 474
    Points : 36 571
    Points
    36 571
    Par défaut
    Citation Envoyé par JaCaDi Voir le message
    En fait dans mon script php, je fais un echo 0 si c'est bon et un echo 'ERREUR' si ce n'est pas bon.

    Ce n'est peut-être pas une bonne idée.
    Disons que ça serait plus sûr en ayant la logique inverse génère un "OK" quand c'est bon et modifie ton test en
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if(xhr_object.responseText == "OK")
    Le problème du "0" (outre le fait que responseText est du string et que tu testais une valeur numérique, ce qui était l'objet de ma remarque initiale) et que cela peut correspondre à de nombreuses valeurs valides (un nombre de lignes, un identifiant, un montant etc.).

    Quant à l'autre test possible
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if(xhr_object.responseText != "ERREUR")
    il est également incertain car, suivant le niveau auquel intervient l'erreur (le bug, en l'occurrence), ton serveur n'aura peut être pas eu le loisir de générer la réponse que tu attends (exemple : une erreur de syntaxe PHP en amont du echo)

    A+

  10. #10
    Membre expérimenté
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    1 132
    Détails du profil
    Informations personnelles :
    Âge : 52
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 132
    Points : 1 418
    Points
    1 418
    Par défaut
    Citation Envoyé par JaCaDi Voir le message
    J'aimerais bien tester cette solution mais... je ne vois pas du tout quoi mettre dans cette saleté de callback, même si je suis d'accord sur le fait que ce soit beaucoup plus propre.
    Grosso-modo en partant de ton code (et sans avoir testé, tu aurais quelque chose du genre ...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
     
    var xhr_object = null;
    var checkboxes = document.getElementsByName('le_groupe_de_checkboxes');
    var iOk = 0;
    var iErr = 0;
    var iCheck = 0;
     
    function callback_sendDone() {
    	if(xhr_object.readyState == 4)
    	{		
    		if(xhr_object.responseText == 0)
    		{
    			iOk++;
    			lblOk.innerHTML = iOk;
    		}
    		else
    		{
    			iErreur++;
    			lblErreur.innerHTML = iErreur;
    		}
     
    		// devyan : on passe à la "checkbox" suivante 
    		++iCheck
    		findAndSendNextCheckbox();
    	}	
    }
     
    // devyan : recherche de la prochaine checkbox cochée et appel ajax
    function findAndSendNextCheckbox() {
    	while (iCheck < checkboxes.length) {
    		// devyan : éliminons les "checkbox" qui ne sont pas cochées
    		if (checkboxes[iCheck].checked != true) {
    			++iCheck;
    			continue;
    		}
     
    		// devyan : si on arrive là alors on a trouvé une "checkbox" cochée à envoyer donc allons-y
    		no_cache = Math.random();
    		//récupérer les valeurs
    		var sendData = "idRub=" + checkboxes[iCheck].value + "&idDest=" + idDest + "&idSource=" + idSource + "&nocache=" +no_cache; // défini plus haut dans le script / sans intérêt pour mon pb
    		xhr_object.open('post', 'duplicate.php',true);
     
    		xhr_object.onreadystatechange = callback_sendDone; 
     
    		xhr_object.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    		xhr_object.send(sendData);
    	}
    }
     
    function sendCheckboxes() { 
    	if(window.XMLHttpRequest) // Firefox 
    		xhr_object = new XMLHttpRequest(); 
    	else if(window.ActiveXObject) // Internet Explorer 
    		xhr_object = new ActiveXObject("Microsoft.XMLHTTP"); 
    	else { // XMLHttpRequest non supporté par le navigateur 
    		alert("Votre navigateur ne supporte pas cette fonctionnalité du site."); 
    		return; 
    	}
     
    	// devyan : appel pour le premier envoi
    	iOk = 0;
    	iErr = 0;
    	iCheck = 0;
    	findAndSendNextCheckbox();
    }
    Sinon, tu as aussi la possibilité (pour la diminuer le nombre d'appels) d'envoyer ta requête par lots.

    En fait, tu détermines quel nombre maximum de "cases à cocher" peuvent être traitées en une seule fois. (par exemple disons qu'avec 10 tu as un bon délais de réponse)

    A partir de là au lieu de faire 1000 requêtes AJAX, tu n'aurais plus qu'à en faire 100

    devyan

  11. #11
    Membre expérimenté
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    1 132
    Détails du profil
    Informations personnelles :
    Âge : 52
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 132
    Points : 1 418
    Points
    1 418
    Par défaut
    Y'a eu du changement le temps que je code mon exemple

  12. #12
    Expert éminent sénior

    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    13 474
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2007
    Messages : 13 474
    Points : 36 571
    Points
    36 571
    Par défaut
    Citation Envoyé par devyan Voir le message
    Y'a eu du changement le temps que je code mon exemple
    Pour une fois que c'est pas moi qui me fait griller

    2 version pour le prix d'une, donc !

    @JaCaDi > un truc que tu devrais prévoir, c'est de désactiver tes checkbox lors de l'appel Ajax.
    En effet, en asynchrone, l'utilisateur garde la main pendant le traitement. Aussi, pendant le traitement en cours, il pourra cocher de nouvelles checkbox. Or celle-ci ne seront pas prises en compte puisque la liste à traiter a déjà était récupérée (et en cours de traitement, donc) à cet instant.
    Il aura donc sous les yeux des informations ne correspondant pas au traitement réellement effectué, ce qui peut être gênant.
    En l'empêchant d'en cocher de nouvelles une fois le traitement Ajax démarré, tu lèverais cette ambiguïté

    A+

  13. #13
    Membre averti
    Avatar de Psycadi
    Homme Profil pro
    Chef de projet - Expert en message box
    Inscrit en
    Juillet 2003
    Messages
    147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet - Expert en message box

    Informations forums :
    Inscription : Juillet 2003
    Messages : 147
    Points : 364
    Points
    364
    Par défaut
    Merci à vous.

    Je suis en train de tester la méthode de E.Bzz, je fais l'affichage de d'état d'avancement.

    Ensuite, je ferai la méthode de devyan.

    Pour le coup de passer plusieurs "traitements" dans une seule requête HTTP. Il faut que je trouve le bon équilibre entre les 2.

    J'ai une fonction qui s'occupe de cacher les bon div (cases à cocher, bouton...).

    Merci aussi pour l'aide sur le xhr_object.responseText, je vais mettre 'OK'.

    Tu as raison pour le typage mais je trouve tellement absurde de ne pas typer les variables que j'ai zappé (et dire qu'on gueule sur les Variant de VB...).

    Je passerai le topic en résolu quand j'aurais ma solution qui marche.

    Merci encore

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Comment éviter des requêtes dans une boucle
    Par dam28800 dans le forum Langage
    Réponses: 43
    Dernier message: 04/12/2008, 16h53
  2. Problème de requête dans une boucle avec ADOQuery
    Par Ekik dans le forum Bases de données
    Réponses: 8
    Dernier message: 14/05/2007, 16h07
  3. Lancer des applications dans une application
    Par n_nikko dans le forum Windows Forms
    Réponses: 3
    Dernier message: 23/03/2007, 20h53
  4. Afectation des variables dans une boucle
    Par Yoni Lebene dans le forum Delphi
    Réponses: 3
    Dernier message: 05/01/2007, 18h52

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo