illcp: AJAX - onreadystatechange im Firefox

Hallo,

ich werde momentan wahnsinnig mit dem AJAX-Verhalten des Firefox bzw. dessen Umgang mit dem onreadystatechange-Event. Folgendes Beispiel:

  
<html>  
<head>  
 <script type="text/javascript">  
  
[code lang=javascript]  
 var ajax = null;  
  
 if (typeof XMLHttpRequest != 'undefined')  
 {  
  ajax = new XMLHttpRequest();  
 }  
  
 if (!ajax)  
 {  
  try  
  {  
   ajax = new ActiveXObject("Msxml2.XMLHTTP");  
  }  
  
  catch(e)  
  {  
   try  
   {  
    ajax = new ActiveXObject("Microsoft.XMLHTTP");  
   }  
  
   catch(e)  
   {  
    ajax = null;  
    window.alert('Ihr Browser unterstuetzt keine AJAX-Funktionalitaet. Wir empfehlen, einen aktuellen Browser zu verwenden.');  
   }  
  }  
 }  
  
  
 function funktionEins()  
 {  
  if(ajax)  
  {  
   ajax.open('POST', 'target.php', true);  
   ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");  
  
   ajax.onreadystatechange = function()  
   {  
    if(ajax.readyState == 4)  
    {  
     alert("Funktion 1");  
     loremIpsum();  
    }  
   };  
  
   ajax.send(null);  
  }  
 }  
  
  
  
 function loremIpsum()  
 {  
  if(ajax)  
  {  
   ajax.open('POST', 'target.php', true);  
   ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");  
  
   ajax.onreadystatechange = function()  
   {  
    if(ajax.readyState == 4)  
    {  
     alert("Lorem Ipsum");  
    }  
   };  
  
   ajax.send(null);  
  }  
 }  
 

</script>

</head>

<body>

<input type="button" value="Funktion 1" onclick="funktionEins()" />
</body>

</html>

[/code]

Der Knackpunkt besteht darin, dass hier eine AJAX-Funktion aus einer AJAX-Funktion heraus aufgerufen wird.

Klickt man im IE 7 auf den Button, wird "Funktion 1" - "Lorem Ipsum" ausgegeben - wie man es erwarten würde.

Der Firefox 2.0 gibt folgendes aus: "Funktion 1" - "Funktion 1" - "Lorem Ipsum".

D.h. der onreadystatechange-Handler von funktionEins() fängt hier im Firefox das neue Request (bzw. das stateChange-Event) aus loremIpsum() ab und reagiert darauf - aber nur beim ersten Mal...?! Ich begreife die Logik nicht - wenn der Handler einer "übergeordneten" AJAX-Funktion auf ein Request einer von ihm aufgerufenen AJAX-Funktion reagiert, müsste das Resultat doch eine Endlosschleife sein, weil immer wieder loremIpsum() ausgeführt werden sollte, was wiederum eine stateChange-Event triggert, welches wieder von funktionEins() abgefangen wird etc. ?!

Um beide Browser dazu zu bringen, das gleiche zu tun, bediene ich mich momentan eines "schmutzigen Tricks" - ich mache mir eine Funktion newAjaxInstance(), die der globalen Variable ajax ein neues XMLHttpRequest-Objekt zuweist, also:

  
function newAjaxInstance()  
 {  
  if (typeof XMLHttpRequest != 'undefined')  
  {  
   ajax = new XMLHttpRequest();  
  }  
  
  if (!ajax)  
  {  
   try  
   {  
    ajax = new ActiveXObject("Msxml2.XMLHTTP");  
   }  
  
   catch(e)  
   {  
    try  
    {  
     ajax = new ActiveXObject("Microsoft.XMLHTTP");  
    }  
  
    catch(e)  
    {  
     ajax = null;  
     window.alert('Ihr Browser unterstuetzt keine AJAX-Funktionalitaet. Wir empfehlen, einen aktuellen Browser zu verwenden.');  
    }  
   }  
  }  
 }  
  

Diese Funktion rufe ich in der onreadystatechange-Funktion von funktionEins() auf.

Tue ich das, verhält sich der FF wie der IE und gibt "Funktion 1" - "Lorem Ipsum" aus. Nur ist diese "Holzhammer"-Vorgehensweise vermutlich nicht allzu elegant... Gibt es evtl. eine andere Möglichkeit dem Firefox beizubringen, nicht mehr auf "untergeordnete" readyStateChanges zu reagieren? Werde ich den Handler der "übergeordneten" Funktion auch anders los?

Gruß,

Christian

  1. Klickt man im IE 7 auf den Button, wird "Funktion 1" - "Lorem Ipsum" ausgegeben - wie man es erwarten würde.

    Der Firefox 2.0 gibt folgendes aus: "Funktion 1" - "Funktion 1" - "Lorem Ipsum".

    Wenn ich deinen Code benutze gibt FF bei mir "Funktion 1" - "Lorem Ipsum" aus, also genau das was du erwartest.

    Prinzipiell würde ich sowas auch sauberer Umsetzen, z.b. ein selbstgeschriebenes AJAX Objekt erzeugen, dem du beim Request eine Callback Funktion übergibst, die dann beim onready Event aufgerufen wird.

    Also so etwas in der Art (schematisch)

    function myAjax() {  
       var ajax_obj = new XMLHttpRequest();  
       var callback;  
       var isActive = false;  
       ajax_obj.onreadystate = function() {  
          if(ajax_obj.readyState == 4) {  
             isActive = false;  
             if(callback) callback();  
          }  
       };  
       this.send = function(url, cb) {  
          if(isActive) return false;  
          isActive = true;  
          if(cb) callback = cb;  
          // .. AJAX operationen ..  
       };  
      
    }
    

    Struppi.

    1. Wenn ich deinen Code benutze gibt FF bei mir "Funktion 1" - "Lorem Ipsum" aus, also genau das was du erwartest.

      Gibt's doch nicht... ich arbeite hier lokal mit XAMPP und hab's gerade mal über's Netzwerk mit einem anderen Rechner und dem Firefox probiert - tatsächlich: der Firefox gibt nur lokal bei mir zweimal "Funktion 1" aus...

      Sowohl hier als auch auf dem anderen Rechner ist's Version 2.0.0.11
      Lade ich den Kram auf meinen Webspace, macht mein Firefox es trotzdem falsch. Ich werd' bekloppt...

      Scheinbar liegt es also ausschließlich an meiner Firefox-Installation - äußerst seltsam.

      Vielen Dank für den Hinweis, damit kann ich das Problem schonmal eingrenzen!

      1. *GRBML*... ich hab' gerade herausgefunden, warum das FireBug-Plugin FireBUG heißt...

        Das ist nämlich offenbar schuld an dem seltsamen AJAX-Verhalten. Wenn ich das Plugin deinstalliere, bekomme ich "Funktion 1" - "Lorem Ipsum", mit installiertem FireBug "Funktion 1" - "Funktion 1" - "Lorem Ipsum".

        Bug im FireBug?!

  2. frei mal drauf los geraten: vielleicht könnte es Probleme verursachen wenn du bei einem neuen Request die ajax-Variable nicht neu definierst.

    Also wird bei einer Funktion die einen Request absetzt zuerst die Variable neu definiert (mit ner Funktion die natürlich auch den Browser überprüft und die Variable per Return übergibt):

    var ajax=getAJAXObject();